diff --git a/ks_dashboard_ninja/__manifest__.py b/ks_dashboard_ninja/__manifest__.py index 91a415f80..ab10361df 100644 --- a/ks_dashboard_ninja/__manifest__.py +++ b/ks_dashboard_ninja/__manifest__.py @@ -1,32 +1,29 @@ # -*- coding: utf-8 -*- { - 'name': 'Dashboard Ninja', + 'name': 'Dashboard Ninja with AI', - 'summary': """ - KS Dashboard Ninja - """, + 'summary': """Dashboard Ninja v17""", - 'description': """ - Dashboard Ninja v17 -""", + 'description': """Dashboard Ninja v17""", 'author': 'Ksolves India Ltd.', 'license': 'OPL-1', - 'website': 'https://store.ksolves.com/', 'maintainer': 'Ksolves India Ltd.', - 'category': 'public_pur', + 'live_test_url': 'https://dashboardninja17.ksolves.net/', + + 'category': 'Services', 'version': '17.0.1.8.3', 'support': 'sales@ksolves.com', 'images': ['static/description/Independence_sale.jpg'], - 'depends': ['base', 'web', 'base_setup', 'bus', 'base_geolocalize'], + 'depends': ['base', 'web', 'base_setup', 'bus','base_geolocalize'], 'data': [ 'security/ir.model.access.csv', @@ -52,27 +49,83 @@ 'demo': ['demo/ks_dashboard_ninja_demo.xml'], 'assets': { - 'web.assets_backend':[ - # 'ks_dashboard_ninja/static/lib/css/Chart.css', - 'ks_dashboard_ninja/static/lib/css/gridstack.min.css', - 'ks_dashboard_ninja/static/lib/js/gridstack-h5.js', - # 'ks_dashboard_ninja/static/lib/js/Chart.bundle.min.js', - 'ks_dashboard_ninja/static/lib/js/chart.umd.min.js', - 'ks_dashboard_ninja/static/lib/js/exporting.js', - 'ks_dashboard_ninja/static/lib/js/pdfmake.min.js', - 'ks_dashboard_ninja/static/src/css/*', - 'ks_dashboard_ninja/static/src/scss/*', - 'ks_dashboard_ninja/static/src/dashboard/*', - 'ks_dashboard_ninja/static/src/items/*', - 'ks_dashboard_ninja/static/src/items/**/*', - 'ks_dashboard_ninja/static/src/preview/*', - 'ks_dashboard_ninja/static/src/tools/*', - # 'ks_dashboard_ninja/static/src/**/**/*', + 'ks_dashboard_ninja.ks_dashboard_lib': [ + '/ks_dashboard_ninja/static/lib/css/gridstack.min.css', + '/ks_dashboard_ninja/static/lib/js/gridstack-h5.js', + '/ks_dashboard_ninja/static/lib/js/pdfmake.min.js', + '/ks_dashboard_ninja/static/lib/js/vfs_fonts.js', + 'ks_dashboard_ninja/static/lib/js/Animated.js', + 'ks_dashboard_ninja/static/lib/js/worldLow.js', + 'ks_dashboard_ninja/static/lib/js/map.js', + 'ks_dashboard_ninja/static/lib/js/index.js', + 'ks_dashboard_ninja/static/lib/js/pdfmake.js', + 'ks_dashboard_ninja/static/lib/js/percent.js', + 'ks_dashboard_ninja/static/lib/js/pdf.min.js', + 'ks_dashboard_ninja/static/lib/js/print.min.js', + 'ks_dashboard_ninja/static/lib/js/Dataviz.js', + 'ks_dashboard_ninja/static/lib/js/Material.js', + 'ks_dashboard_ninja/static/lib/js/Moonrise.js', + 'ks_dashboard_ninja/static/lib/js/xy.js', + 'ks_dashboard_ninja/static/lib/js/radar.js', ], - }, + 'web.assets_backend': [ + 'ks_dashboard_ninja/static/src/css/ks_dashboard_ninja.scss', + 'ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_item.css', + 'ks_dashboard_ninja/static/src/css/ks_icon_container_modal.css', + 'ks_dashboard_ninja/static/src/css/ks_dashboard_item_theme.css', + 'ks_dashboard_ninja/static/src/css/ks_input_bar.css', + 'ks_dashboard_ninja/static/src/css/ks_ai_dash.css', + 'ks_dashboard_ninja/static/src/css/ks_dn_filter.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_map_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/lib/css/Chart.min.css', + 'ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js', + 'ks_dashboard_ninja/static/src/js/ks_global_functions.js', + 'ks_dashboard_ninja/static/lib/js/index.js', + 'ks_dashboard_ninja/static/lib/js/pdfmake.js', + 'ks_dashboard_ninja/static/lib/js/percent.js', + 'ks_dashboard_ninja/static/lib/js/pdf.min.js', + 'ks_dashboard_ninja/static/lib/js/print.min.js', + 'ks_dashboard_ninja/static/lib/js/Dataviz.js', + 'ks_dashboard_ninja/static/lib/js/Material.js', + 'ks_dashboard_ninja/static/lib/js/Moonrise.js', + 'ks_dashboard_ninja/static/lib/js/exporting.js', + 'ks_dashboard_ninja/static/lib/js/pdfmake.js', + 'ks_dashboard_ninja/static/lib/js/percent.js', + 'ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js', + 'ks_dashboard_ninja/static/src/js/ks_global_functions.js', + 'ks_dashboard_ninja/static/src/js/ks_form_view_dialog.js', + 'ks_dashboard_ninja/static/lib/js/xy.js', + 'ks_dashboard_ninja/static/lib/js/radar.js', + 'ks_dashboard_ninja/static/src/css/style.css', + # 'ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js', + # 'ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js', + 'ks_dashboard_ninja/static/src/js/ks_filter_props_new.js', + 'ks_dashboard_ninja/static/src/js/domainfix.js', + # 'ks_dashboard_ninja/static/src/js/ks_dashboard_item_theme.js', + # 'ks_dashboard_ninja/static/src/js/ks_import_dashboard.js', + # 'ks_dashboard_ninja/static/src/js/ks_domain_fix.js', + # 'ks_dashboard_ninja/static/src/js/ks_quick_edit_view.js', + # 'ks_dashboard_ninja/static/src/js/ks_date_picker.js', + + # 'ks_dashboard_ninja/static/lib/js/Chart.bundle.min.js', + 'ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_pro.css', + 'ks_dashboard_ninja/static/src/css/ks_to_do_item.css', + # 'ks_dashboard_ninja/static/src/js/ks_item_theme_file.js', + # 'ks_dashboard_ninja/static/src/xml/owl_template.xml', + 'ks_dashboard_ninja/static/src/xml/**/*', + 'ks_dashboard_ninja/static/src/css/ks_radial_chart.css', + 'ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js', + 'ks_dashboard_ninja/static/src/components/**/*', + 'ks_dashboard_ninja/static/src/widgets/**/*', + ], + }, 'external_dependencies': { - 'python': ['pandas','xlrd'] + 'python': ['pandas','xlrd','openpyxl','gTTS'] }, 'uninstall_hook': 'uninstall_hook', diff --git a/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py b/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py index e0971409d..2f6be1d91 100644 --- a/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py +++ b/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py @@ -6,9 +6,11 @@ from odoo.exceptions import ValidationError from datetime import timedelta import pytz import os +import ast import os.path from dateutil import rrule from dateutil.relativedelta import relativedelta +from odoo.tools.safe_eval import safe_eval @@ -36,11 +38,10 @@ def ks_get_date(ks_date_filter_selection, self, type): series = ks_date_filter_selection if ks_date_filter_selection in ['t_fiscal_year', 'n_fiscal_year', 'ls_fiscal_year']: function_name = globals()["ks_date_series_" + series.split("_")[0]] - return function_name(series.split("_")[1], timezone, type, self) + return function_name(series.split("_")[1], timezone, type,self) else: function_name = globals()["ks_date_series_" + series.split("_")[0]] - return function_name(series.split("_")[1], timezone, type, self) - + return function_name(series.split("_")[1],timezone, type,self) def ks_date_series_td(ks_date_selection, timezone, type, self=None): ks_function_name = globals()["ks_get_date_range_from_td_" + ks_date_selection] diff --git a/ks_dashboard_ninja/controllers/__init__.py b/ks_dashboard_ninja/controllers/__init__.py index fa2f9cbfd..798bc50c4 100644 --- a/ks_dashboard_ninja/controllers/__init__.py +++ b/ks_dashboard_ninja/controllers/__init__.py @@ -1,3 +1,4 @@ from . import ks_chart_export from . import ks_list_export -from . import ks_dashboard_export \ No newline at end of file +from . import ks_dashboard_export +from . import ks_domain_fix \ No newline at end of file diff --git a/ks_dashboard_ninja/controllers/ks_chart_export.py b/ks_dashboard_ninja/controllers/ks_chart_export.py index dbd400b6b..830a8d102 100644 --- a/ks_dashboard_ninja/controllers/ks_chart_export.py +++ b/ks_dashboard_ninja/controllers/ks_chart_export.py @@ -22,6 +22,10 @@ class KsChartExport(http.Controller): params = json.loads(data) header,chart_data = operator.itemgetter('header','chart_data')(params) chart_data = json.loads(chart_data) + + if isinstance(chart_data['labels'], list): + chart_data['labels'] = [str(label) for label in chart_data['labels']] + chart_data['labels'].insert(0,'Measure') columns_headers = chart_data['labels'] import_data = [] @@ -37,9 +41,6 @@ class KsChartExport(http.Controller): # cookies={'fileToken': token} ) - - - class KsChartExcelExport(KsChartExport, http.Controller): # Excel needs raw data to correctly handle numbers and date values diff --git a/ks_dashboard_ninja/controllers/ks_domain_fix.py b/ks_dashboard_ninja/controllers/ks_domain_fix.py new file mode 100644 index 000000000..b4fb31dcd --- /dev/null +++ b/ks_dashboard_ninja/controllers/ks_domain_fix.py @@ -0,0 +1,21 @@ +from odoo.addons.web.controllers.domain import Domain + +from odoo import http, _ +from odoo.http import Controller, request +from odoo.tools.safe_eval import safe_eval + + +class ksdomainfix(Domain): + # to validate our uid and mycompany based domain + @http.route('/web/domain/validate', type='json', auth="user") + def validate(self, model, domain): + ks_uid_domain = str(domain) + if ks_uid_domain and "%UID" in ks_uid_domain: + ks_domain = ks_uid_domain.replace("%UID", str(request.env.user.id)) + return super().validate(model,safe_eval(ks_domain)) + elif ks_uid_domain and "%MYCOMPANY" in ks_uid_domain: + ks_domain = ks_uid_domain.replace("%MYCOMPANY", str(request.env.company.id)) + return super().validate(model,safe_eval(ks_domain)) + else: + return super().validate(model, domain) + diff --git a/ks_dashboard_ninja/controllers/ks_list_export.py b/ks_dashboard_ninja/controllers/ks_list_export.py index 6802a8217..e5477a21f 100644 --- a/ks_dashboard_ninja/controllers/ks_list_export.py +++ b/ks_dashboard_ninja/controllers/ks_list_export.py @@ -5,7 +5,7 @@ import json import operator import logging from odoo.addons.web.controllers.main import ExportFormat, ExportXlsxWriter -from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT +from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT , xlsxwriter import datetime from odoo import http from odoo.http import content_disposition, request diff --git a/ks_dashboard_ninja/data/ks_default_data.xml b/ks_dashboard_ninja/data/ks_default_data.xml index e11dca970..634d3e832 100644 --- a/ks_dashboard_ninja/data/ks_default_data.xml +++ b/ks_dashboard_ninja/data/ks_default_data.xml @@ -242,7 +242,7 @@ [["id","<",40]] - warm + dark ks_bar_chart @@ -258,7 +258,7 @@ [["id","<",10]] - warm + dark ks_line_chart @@ -296,7 +296,7 @@ [["id","<",10]] - neon + material ks_horizontalBar_chart @@ -308,7 +308,7 @@ [["id","<",10]] - cool + moonrise ks_polarArea_chart @@ -320,7 +320,7 @@ [["id","<",10]] - neon + moonrise 100 1 monetary @@ -363,7 +363,7 @@ [["id","<",10]] - neon + dark ks_pie_chart @@ -374,7 +374,7 @@ - neon + default ks_area_chart @@ -468,7 +468,7 @@ 1 - warm + material 10 1 monetary @@ -497,7 +497,7 @@ - warm + material 25 1 monetary @@ -511,7 +511,7 @@ - warm + moonrise 10 1 monetary @@ -525,7 +525,7 @@ - neon + default 1 25 1 diff --git a/ks_dashboard_ninja/i18n/zh_CN.po b/ks_dashboard_ninja/i18n/zh_CN.po index a52511560..0bc286c43 100644 --- a/ks_dashboard_ninja/i18n/zh_CN.po +++ b/ks_dashboard_ninja/i18n/zh_CN.po @@ -4,13 +4,13 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" +"Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-05-26 14:51+0000\n" -"PO-Revision-Date: 2024-08-22 15:49+0800\n" +"POT-Creation-Date: 2024-10-03 02:05+0000\n" +"PO-Revision-Date: 2024-10-03 10:06+0800\n" "Last-Translator: \n" "Language-Team: \n" -"Language: zh_CN\n" +"Language: zh\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -19,6 +19,7 @@ msgstr "" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_dashboard_board_id +#, fuzzy msgid "" "\n" " Items Configuration and their position in the dashboard will be copied from the selected " @@ -27,35 +28,40 @@ msgid "" " " msgstr "" "\n" -" 项目配置及其在仪表板中的位置将从所选仪表板中复制,并保存为模板。\n" -" 并保存为模板。\n" +"项目配置及其在仪表板中的位置将从选定的仪表板中复制\n" +" 并将另存为 template。\n" " " #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_previous_period +#, fuzzy msgid " Compare With Previous Period " -msgstr "与前期比较" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_update_items_data -msgid " Data will be refreshed after the selected interval." -msgstr "数据将在所选时间间隔后刷新。" +msgstr "与上一期间比较" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_relation_groupby +#, fuzzy msgid " Define the x-axis of the graph. " msgstr "定义图形的 x 轴。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_year_period +#, fuzzy msgid " Display the record for the same Date field for the last year. " -msgstr "显示去年同一日期字段的记录。" +msgstr "显示去年同一 Date 字段的记录。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_show_data_value msgid " Display value on the graph. . " msgstr "在图表上显示数值.." +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 +#, python-format +msgid " Negative periods are not allowed " +msgstr "不允许出现负数期间。" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__ls_pastwithout_now #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__ls_pastwithout_now @@ -65,39 +71,46 @@ msgstr "过去(不包括今日)" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_compare_period +#, fuzzy msgid " Provide the number of Date Filter Selection you want to include while displaying the record." -msgstr "提供您希望在显示记录时包含的日期筛选器选择数量。" +msgstr "提供在显示记录时要包含的 Date Filter Selection (日期筛选器选择) 的数量。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_data_limit +#, fuzzy msgid " Records to be displayed on the graph" -msgstr "图表上要显示的记录" +msgstr "要在图表上显示的记录" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_background_color #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_header_bg_color +#, fuzzy msgid " Select the background color with transparency. " -msgstr "选择透明背景色。" +msgstr "选择具有透明度的背景色。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_fields +#, fuzzy msgid " Select the fields you want to display in the list. " -msgstr "选择要在列表中显示的字段。 " +msgstr "选择要在列表中显示的字段。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_layout +#, fuzzy msgid " Select the layout to display records. " msgstr "选择显示记录的布局。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_sort_by_order +#, fuzzy msgid " Select the order of the sorting. " msgstr "选择排序顺序。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_target_view +#, fuzzy msgid " Select the view to compare target with data." -msgstr "选择视图,将目标与数据进行比较。" +msgstr "选择视图以将目标与数据进行比较。" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_relation_sub_groupby @@ -105,53 +118,87 @@ msgid " Sub Group By" msgstr "次级分组" #. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_auto_update_type__ks_update_interval -msgid " Update after the selected interval" -msgstr "选定时间间隔后更新" +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#, fuzzy, python-format +msgid "%s model does not exist.Please install" +msgstr "%s模型不存在。请安装" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, fuzzy, python-format +msgid "(ev)=>self.kslayout(ev)" +msgstr "(ev)=>self.kslayout(ev)" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/domainfix.js:0 +#, fuzzy, python-format +msgid "(no result)" +msgstr "(无结果)" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_set_interval__60000 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_update_items_data__60000 msgid "1 minute" msgstr "1分钟" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_set_interval__600000 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_update_items_data__600000 msgid "10 minute" msgstr "10分钟" +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__res_config_settings__ks_analysis_word_length__100 +#, fuzzy +msgid "100 words" +msgstr "100 字" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_set_interval__15000 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_update_items_data__15000 msgid "15 Seconds" msgstr "15秒" +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__res_config_settings__ks_analysis_word_length__150 +#, fuzzy +msgid "150 words" +msgstr "150 字" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_set_interval__120000 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_update_items_data__120000 msgid "2 minute" msgstr "2分钟" +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__res_config_settings__ks_analysis_word_length__200 +#, fuzzy +msgid "200 words" +msgstr "200 字" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_set_interval__30000 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_update_items_data__30000 msgid "30 Seconds" msgstr "30秒" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_set_interval__45000 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_update_items_data__45000 msgid "45 Seconds" msgstr "45秒" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_set_interval__300000 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_update_items_data__300000 msgid "5 minute" msgstr "5分钟" #. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__res_config_settings__ks_analysis_word_length__50 +#, fuzzy +msgid "50 words" +msgstr "50 字" + +#. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 #, python-format msgid "" @@ -163,10 +210,124 @@ msgstr "" " 您可以在这里找到与“仪表板”相关的所有项目。

\n" " " +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "" +"\n" +" **File names should not contain any special characters. File " +"name can have\n" +" Spaces or separated by Underscores(_).\n" +" " +msgstr "" +"" +"文件名不应包含任何特殊字符。文件名可以具有\n" +" 空格或用下划线 (_) 分隔。 " + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "" +"\n" +" **Field in sort by column must match atleast one " +"field given in\n" +" measures column.\n" +" " +msgstr "" +"**排序依据列中的字段必须至少匹配\n" +" measures " +"列。 " + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "" +"\n" +" ** Please enter positive standard target.\n" +" " +msgstr "" +"** 请输入正标准目标。 " + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +#, fuzzy +msgid "Generate items with AI" +msgstr "使用 AI 生成项目" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "Preview" +msgstr "预览" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_ai_analysis +#, fuzzy +msgid "AI Analysis" +msgstr "AI 分析" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_res_config_settings__ks_analysis_word_length +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.res_config_settings_inherit_view +#, fuzzy +msgid "AI Analysis length" +msgstr "AI 分析长度" + +#. module: ks_dashboard_ninja +#: model:ir.actions.act_window,name:ks_dashboard_ninja.ks_dashboard_ninja_ai_action +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_ai_dashboard +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_arti_int +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_ai_whole_dashboard_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +#, fuzzy +msgid "AI Dashboard" +msgstr "AI 仪表板" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#: code:addons/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py:0 +#, fuzzy, python-format +msgid "AI Responds with the following status:- %s" +msgstr "AI 响应以下状态:- %s" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#, fuzzy, python-format +msgid "AI Responds with the wrong analysis. Please try again " +msgstr "AI 以错误的分析作为回应。请重试" + +#. module: ks_dashboard_ninja +#: model:ir.actions.act_window,name:ks_dashboard_ninja.ks_dashboard_ninja_ai_dashboardaction +#, fuzzy +msgid "AI whole Dashboard" +msgstr "AI 整个仪表板" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__ks_action +#, fuzzy msgid "Action" -msgstr "行动" +msgstr "操作" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_item_action_field @@ -179,11 +340,18 @@ msgid "Action Lines" msgstr "操作明细" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 #, python-format msgid "Action field: {} cannot be aggregated by {}" msgstr "操作字段: {} 不能按{} 生成" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_action_item_name +#, fuzzy +msgid "Action item name" +msgstr "操作项名称" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_actions #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view @@ -194,27 +362,22 @@ msgstr "操作" #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_active #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_is_active #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy msgid "Active" -msgstr "" +msgstr "激活" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__ks_active +#, fuzzy msgid "Active Description" -msgstr "" +msgstr "活动描述" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Add" -msgstr "添加" - -#. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Add Item" -msgstr "添加物料" +msgstr "添加项目" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view @@ -227,8 +390,8 @@ msgid "Add a Section" msgstr "添加区块" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Add a condition" msgstr "添加条件" @@ -244,7 +407,7 @@ msgid "Add a separator" msgstr "添加分隔符" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Add button" @@ -252,18 +415,29 @@ msgstr "添加按钮" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy msgid "Advance Configuration" -msgstr "" +msgstr "高级配置" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_form +msgid "Advance Settings" +msgstr "高级设置" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy msgid "" -"All Target Lines Changes Will be reflected on Chart after saving the record and pagination will be " -"ignore ." -msgstr "保存记录后,所有目标行更改都将反映在图表上,分页将被忽略。" +"All Target Lines Changes Will be reflected on Chart after saving the record\n" +" and\n" +" pagination will be ignore ." +msgstr "" +"保存记录后,所有 Target Lines 更改都将反映在 Chart 上\n" +" 和\n" +" pagination 将被忽略。" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__l_none #, python-format @@ -271,57 +445,80 @@ msgid "All Time" msgstr "所有时间" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#, python-format -msgid "All items can not be Imported" -msgstr "所有不能导入的项目" +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board__multi_layouts +#, fuzzy +msgid "Allow user to have multiple layouts of the same Dashboard" +msgstr "允许用户拥有同一 Dashboard 的多个布局" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 #, python-format msgid "Apply" msgstr "应用" #. module: ks_dashboard_ninja -#. openerp-web +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_multiplier_active +#, fuzzy +msgid "Apply Multiplier" +msgstr "Apply 乘数" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 #, python-format msgid "Archive" msgstr "存档" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#, python-format +#, fuzzy, python-format msgid "Are you sure that you want to archive all the selected records?" -msgstr "您确定要存档所有选定的记录吗?" +msgstr "是否确实要存档所有选定的记录?" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#, fuzzy, python-format +msgid "Are you sure that you want to remove this item?" +msgstr "是否确实要删除此项目?" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_delete_dashboard_wizard_form +#, fuzzy, python-format +msgid "Are you sure you want to delete this dashboard ?" +msgstr "是否确实要删除此仪表板 ?" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 #, python-format msgid "Are you sure you want to remove this item?" msgstr "您确定要删除此项吗?" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js:0 -#, python-format +#, fuzzy, python-format msgid "Are you sure you want to remove this task?" -msgstr "您确定要删除这项任务吗?" +msgstr "是否确实要删除此任务?" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_area_chart #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_area_chart -#, python-format +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_15 msgid "Area Chart" msgstr "面积图" +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_23 +msgid "Area Chart with data values" +msgstr "包含数据值的区域图" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_sort_by_order__asc #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_sort_by_order__asc @@ -329,21 +526,17 @@ msgid "Ascending" msgstr "升序" #. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_form msgid "Auto Update" msgstr "自动更新" -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_auto_update_type -msgid "Auto Update Type" -msgstr "自动更新类型" - #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_data_count_type__average #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_record_count_type_2__average #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_record_count_type__average +#, fuzzy msgid "Average" -msgstr "一般" +msgstr "平均" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_background_color @@ -351,18 +544,16 @@ msgid "Background Color" msgstr "背景颜色" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_bar_chart #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_bar_chart -#, python-format +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_5 msgid "Bar Chart" msgstr "条形图" #. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_base -msgid "Base" -msgstr "基础" +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_20 +msgid "Bar Chart With Data Values" +msgstr "包含数据值的柱状图" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view @@ -370,11 +561,61 @@ msgid "Below action will be performed at the end of the Drill Down Action" msgstr "向下钻取动作结束时将执行以下动作" #. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, python-format +msgid "Beta" +msgstr "测试版" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__board_type +msgid "Board Type" +msgstr "面板类型" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_bullet_chart +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_bullet_chart +msgid "Bullet Chart" +msgstr "气泡图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_bullet_preview +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "Bullet Preview" +msgstr "Bullet 预览" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__data_source__csv +msgid "CSV" +msgstr "CSV" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__csv_bool +#, fuzzy +msgid "CSV Bool" +msgstr "CSV 布尔值" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_csv_group_by_lines +#, fuzzy +msgid "CSV Group By Lines" +msgstr "CSV 按行分组" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_ai_whole_dashboard_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_create_dashboard_wizard_form #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_action +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_delete_dashboard_wizard_form +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_duplicate_dashboard_wizard_form +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_fetch_key_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_import_dashboard_form_view msgid "Cancel" msgstr "取消" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 #, python-format msgid "" @@ -382,6 +623,7 @@ msgid "" msgstr "当“按日期分组”字段设置为在“分钟和小时”情况下具有聚合时,无法创建目标行。" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 #, python-format msgid "" @@ -390,8 +632,8 @@ msgid "" msgstr "使用每个日期的目标行时,无法设置具有日期时间(小时,分钟)的聚合。 为此,请先删除目标行" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.xml:0 #, python-format msgid "Changing Layout midway will set the default icon colour and font colour for selected layout." msgstr "中途更改布局将为所选布局设置默认的图标颜色和字体颜色。" @@ -408,23 +650,25 @@ msgid "Chart Data in string form" msgstr "字符串形式的图表数据" #. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_show_live_pop_up -msgid "Checkbox to enable notification after every update. " -msgstr "复选框用于启用每次更新后的通知。" +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_previous_period +#, fuzzy +msgid "Checkbox to show comparison between the data of present day and the previous selected period. " +msgstr "显示当前时间段和上一个所选时间段数据之间的比较的复选框。" #. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_previous_period -msgid "Checkbox to show comparison between the data of present day and the previous selected period. " -msgstr "复选框,用于显示当前数据与上一选定时段数据的比较。" +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_child_board__board_type__child +msgid "Child" +msgstr "子级" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_icon_select +#, fuzzy msgid "Choose the Icon option. " -msgstr "选择图标选项。" +msgstr "选择 Icon 选项。" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.xml:0 #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Clear" @@ -441,10 +685,12 @@ msgid "Client Item Action" msgstr "客户端动作" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.xml:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#, python-format +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, fuzzy, python-format msgid "Close" msgstr "关闭" @@ -454,33 +700,60 @@ msgid "Colombian Peso Format" msgstr "哥伦比亚比索格式" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 #, python-format msgid "Color Palette" msgstr "调色板" #. module: ks_dashboard_ninja -#. openerp-web +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "Column Data Type" +msgstr "列数据类型" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 #, python-format msgid "Coming Soon in Future :)" msgstr " 即将推出:)" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__company_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_company_id +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.child_board_tree +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Company" msgstr "公司" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#, python-format +msgid "Company:" +msgstr "公司:" + +#. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_res_config_settings +msgid "Config Settings" +msgstr "配置设置" + #. module: ks_dashboard_ninja #: model:ir.ui.menu,name:ks_dashboard_ninja.configuration_menu msgid "Configuration" msgstr "配置" #. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__cool -msgid "Cool" -msgstr "很酷" +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, fuzzy, python-format +msgid "Configure this dashboard" +msgstr "配置此仪表板" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_data_count_type__count @@ -495,14 +768,65 @@ msgid "Count..." msgstr "总计..." #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_country_id +msgid "Country" +msgstr "国家" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_country_code +msgid "Country Code" +msgstr "国家代码" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#: model:ir.actions.act_window,name:ks_dashboard_ninja.ks_create_dashboard_wizard +#, fuzzy, python-format +msgid "Create Dashboard" +msgstr "创建 Dashboard" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +msgid "Create Table" +msgstr "新建表格" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, fuzzy, python-format +msgid "Create a New Dashboard" +msgstr "创建新控制面板" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, python-format +msgid "Create new chart" +msgstr "创建新图表" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_delete_wizard__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_duplicate_wizard__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_kpi_mail__create_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__create_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__create_uid @@ -510,14 +834,27 @@ msgid "Created by" msgstr "创建人" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_delete_wizard__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_duplicate_wizard__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_kpi_mail__create_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__create_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__create_date @@ -531,10 +868,17 @@ msgstr "累计折线图" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_cumulative_field -msgid "Cumulative Field" -msgstr "累计字段" +#, fuzzy +msgid "Cumulative Fields" +msgstr "累积字段" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_currency_id +msgid "Currency" +msgstr "货币" + +#. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 #, python-format msgid "Current Json File is not properly formatted according to Dashboard Ninja Model." @@ -542,14 +886,17 @@ msgstr "根据仪表板模型,当前的Json文件格式不正确。" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board_template__ks_template_type__ks_custom +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_icon_select__custom #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_unit_selection__custom msgid "Custom" msgstr "自定义" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__l_custom #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__l_custom #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__l_custom @@ -568,22 +915,29 @@ msgid "Custom Query" msgstr "自定义查询" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Customize Dashboard" msgstr "自定义仪表板" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.xml:0 #, python-format msgid "Customize Item" msgstr "自定义项目" +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__dark +msgid "Dark" +msgstr "深色" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__ks_dashboard_board_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_dashboard_board_id @@ -594,10 +948,29 @@ msgstr "自定义项目" msgid "Dashboard" msgstr "仪表盘" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_res_config_settings__dn_api_key +#, fuzzy +msgid "Dashboard AI API Key" +msgstr "仪表板 AI API 密钥" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.res_config_settings_inherit_view +#, fuzzy +msgid "Dashboard API Key" +msgstr "控制面板 API 密钥" + +#. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_wizard +#, fuzzy +msgid "Dashboard Creation Wizard" +msgstr "Dashboard 创建向导" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_custom_filters_ids +#, fuzzy msgid "Dashboard Custom Filters" -msgstr "仪表板自定义过滤器" +msgstr "Dashboard 自定义过滤器" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_defined_filters @@ -605,6 +978,20 @@ msgid "Dashboard Defined Filter" msgstr "筛选" #. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_delete_wizard +#, fuzzy +msgid "Dashboard Delete Wizard" +msgstr "仪表板删除向导" + +#. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_duplicate_wizard +#, fuzzy +msgid "Dashboard Duplicate Wizard" +msgstr "Dashboard Duplicate Wizard" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__ks_dashboard_csv_group_by_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__ks_dashboard_item_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_dashboard_item_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__ks_dashboard_item msgid "Dashboard Item" @@ -625,12 +1012,19 @@ msgstr "仪表板项目图表按类型分组" msgid "Dashboard Item Chart Sub Group By Type" msgstr "仪表板项目图表子类型分组" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__ks_dashboard_group_by_id +#, fuzzy +msgid "Dashboard Item Id" +msgstr "仪表板项目 ID" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_item_type msgid "Dashboard Item Type" msgstr "仪表板项目类型" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 #: model:ir.actions.act_window,name:ks_dashboard_ninja.item_action_window #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_items_ids @@ -646,16 +1040,22 @@ msgstr "仪表盘布局" #. module: ks_dashboard_ninja #: model:ir.ui.menu,name:ks_dashboard_ninja.dashboard_layout_menu +#, fuzzy msgid "Dashboard Layouts" msgstr "仪表板布局" #. module: ks_dashboard_ninja #: model:ir.actions.act_window,name:ks_dashboard_ninja.board_form_tree_action_window +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_create_dashboard_wizard_form +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_delete_dashboard_wizard_form +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_duplicate_dashboard_wizard_form msgid "Dashboard Manager" msgstr "仪表板管理" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__ks_dash_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__name msgid "Dashboard Name" msgstr "仪表板名称" @@ -664,6 +1064,12 @@ msgstr "仪表板名称" msgid "Dashboard Ninja" msgstr "忍者仪表板" +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.res_config_settings_inherit_view +#, fuzzy +msgid "Dashboard Ninja Api Key" +msgstr "Dashboard Ninja Api 密钥" + #. module: ks_dashboard_ninja #: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_child_board msgid "Dashboard Ninja Child Board" @@ -671,13 +1077,22 @@ msgstr "仪表板子面板" #. module: ks_dashboard_ninja #: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_board_custom_filters +#, fuzzy msgid "Dashboard Ninja Custom Filters" -msgstr "仪表板忍者自定义过滤器" +msgstr "Dashboard Ninja 自定义过滤器" #. module: ks_dashboard_ninja #: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_board_defined_filters +#, fuzzy msgid "Dashboard Ninja Defined Filters" -msgstr "仪表板忍者定义的过滤器" +msgstr "Dashboard Ninja 定义的过滤器" + +#. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_csv_group_by +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_group_by +#, fuzzy +msgid "Dashboard Ninja Group By" +msgstr "Dashboard Ninja Group By" #. module: ks_dashboard_ninja #: model:ir.model,name:ks_dashboard_ninja.model_ks_ninja_dashboard_item_action @@ -694,6 +1109,25 @@ msgstr "仪表板忍者物品动作线" msgid "Dashboard Ninja Items Goal Lines" msgstr "仪表盘项目目标线" +#. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_item_multiplier +#, fuzzy +msgid "Dashboard Ninja Items Multiplier Lines" +msgstr "Dashboard Ninja Items 乘数线" + +#. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_kpi_mail +#, fuzzy +msgid "Dashboard Ninja Kpi mail" +msgstr "Dashboard Ninja Kpi 邮件" + +#. module: ks_dashboard_ninja +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_csv_new +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_new +#, fuzzy +msgid "Dashboard Ninja New" +msgstr "Dashboard Ninja 新" + #. module: ks_dashboard_ninja #: model:ir.module.category,name:ks_dashboard_ninja.ks_dashboard_ninja_security_groups msgid "Dashboard Ninja Rights" @@ -711,13 +1145,23 @@ msgstr "仪表板项目" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_defined_filters_ids +#, fuzzy msgid "Dashboard Predefined Filters" -msgstr "仪表板预定义过滤器" +msgstr "Dashboard 预定义过滤器" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, python-format +msgid "Dashboard Setting" +msgstr "仪表盘设置" #. module: ks_dashboard_ninja #: model:ir.actions.act_window,name:ks_dashboard_ninja.template_tree_action_window +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__ks_template #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_default_template #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_board_template_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__ks_template #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_template_form #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_template_tree msgid "Dashboard Template" @@ -725,6 +1169,7 @@ msgstr "仪表板模板" #. module: ks_dashboard_ninja #: model:ir.actions.act_window,name:ks_dashboard_ninja.layout_tree_action_window +#, fuzzy msgid "Dashboard layout" msgstr "仪表板布局" @@ -736,6 +1181,7 @@ msgstr "仪表盘" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy msgid "Data" msgstr "数据" @@ -761,8 +1207,21 @@ msgstr "数据比较" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_measure_field_2 +#, fuzzy msgid "Data Points displayed with a line in the graph. " -msgstr "数据点在图表中以直线显示。" +msgstr "数据点 (Data Points) 在图表中以线条显示。" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__data_source +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +msgid "Data Source" +msgstr "数据源" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_as_of_now +#, fuzzy +msgid "Data Till Now" +msgstr "截至目前的数据" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_data_count_type @@ -772,16 +1231,22 @@ msgstr "数据类型" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_cumulative_field #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_measure_field +#, fuzzy msgid "Data points to be selected." msgstr "要选择的数据点。" #. module: ks_dashboard_ninja +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__ks_model_id +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__ks_import_model_id +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__ks_import_model +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__ks_import_model_id #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__ks_model_id #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_model_id #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_model_id #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_model_id +#, fuzzy msgid "Data source to fetch and read the data for the creation of dashboard items. " -msgstr "数据源,用于获取和读取数据以创建仪表板项目。" +msgstr "数据源,用于获取和读取用于创建仪表板项目的数据。" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__ks_goal_date @@ -789,8 +1254,10 @@ msgid "Date" msgstr "日期" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Date Filter" msgstr "日期筛选" @@ -815,11 +1282,14 @@ msgid "Day" msgstr "天" #. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_child_board__board_type__default #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__default +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_icon_select__default msgid "Default" msgstr "默认" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 #, python-format msgid "Default Dashboard can't be deleted." @@ -830,15 +1300,9 @@ msgstr "无法删除默认仪表板。" msgid "Default Date Filter" msgstr "默认日期过滤器" -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 -#, python-format -msgid "Default Icons" -msgstr "默认图标" - #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_calculation_type__custom +#, fuzzy msgid "Default Query" msgstr "默认查询" @@ -849,23 +1313,39 @@ msgstr "默认更新间隔" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_extension +#, fuzzy msgid "Define conditions for filter to write manually" -msgstr "定义过滤器手动写入的条件" +msgstr "定义筛选条件以手动写入" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_domain #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain +#, fuzzy msgid "Define conditions for filter. " -msgstr "定义过滤器的条件。" +msgstr "定义筛选条件。" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_delete_dashboard_wizard_form #, python-format msgid "Delete" msgstr "删除" +#. module: ks_dashboard_ninja +#: model:ir.actions.act_window,name:ks_dashboard_ninja.ks_delete_dashboard_wizard +#, fuzzy +msgid "Delete Dashboard" +msgstr "删除控制面板" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, python-format +msgid "Delete this dashboard" +msgstr "删除此仪表板" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_sort_by_order__desc #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_sort_by_order__desc @@ -883,7 +1363,12 @@ msgid "Deviation Field" msgstr "误差字段" #. module: ks_dashboard_ninja -#. openerp-web +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_precision_digits +msgid "Digits" +msgstr "位数" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: code:addons/ks_dashboard_ninja/static/src/xml/ks_quick_edit_view.xml:0 #, python-format @@ -891,7 +1376,7 @@ msgid "Discard" msgstr "丢弃" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Discard Changes" @@ -903,14 +1388,27 @@ msgid "Display" msgstr "显示" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_delete_wizard__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_duplicate_wizard__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_kpi_mail__display_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__display_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__display_name @@ -922,11 +1420,27 @@ msgstr "显示名称" msgid "Display Type" msgstr "显示类型" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_as_of_now +#, fuzzy +msgid "Display the total sum of each legends as it grows with times" +msgstr "显示每个图例随时间增长的总和" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_unit +#, fuzzy msgid "Display the unit of the data." msgstr "显示数据的单位。" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#, fuzzy, python-format +msgid "" +"Do you agree that AI should be used to produce the explanation? It will take a few minutes to finish the " +"process?" +msgstr "你同意应该使用 AI 来产生解释吗?完成该过程需要几分钟吗?" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_domain #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain @@ -942,8 +1456,9 @@ msgstr "Domain拓展" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__ks_domain_field_id +#, fuzzy msgid "Domain Field" -msgstr "领域" +msgstr "Domain Field" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_domain_temp @@ -952,52 +1467,103 @@ msgid "Domain Substitute" msgstr "替代域" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_filters.py:0 -#, python-format +#, fuzzy, python-format msgid "Domain can not be empty" msgstr "域不能为空" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_doughnut_chart #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_doughnut_chart -#, python-format msgid "Doughnut Chart" msgstr "环形图" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Drill Up" -msgstr "向上钻" +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_11 +msgid "Doughnut chart" +msgstr "环形图" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_25 +#, fuzzy +msgid "Doughnut semi circle" +msgstr "甜甜圈半圆" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #: model:ir.actions.server,name:ks_dashboard_ninja.ks_duplicate_dashboard #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_ninja_dashboard_item_action__ks_action__duplicate +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_duplicate_dashboard_wizard_form #, python-format msgid "Duplicate" msgstr "复制" #. module: ks_dashboard_ninja -#. openerp-web +#: model:ir.actions.act_window,name:ks_dashboard_ninja.ks_duplicate_dashboard_wizard +#, fuzzy +msgid "Duplicate Dashboard" +msgstr "复制仪表板" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, fuzzy, python-format +msgid "Duplicate current Dashboard" +msgstr "复制当前仪表板" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Edit Layout" msgstr "编辑布局" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js:0 #, python-format msgid "Edit Task" msgstr "编辑任务" +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/res_settings.py:0 +#, fuzzy, python-format +msgid "" +"Either you have entered wrong URL path or there is some problem in sending request. If you need " +"assistance, feel free to contact at sales@ksolves.com" +msgstr "您输入的 URL 路径错误或发送请求时出现问题。如果您需要帮助,请随时联系 sales@ksolves.com" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_email_to_ids +#, fuzzy +msgid "Email Address" +msgstr "电子邮件地址" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__ks_email_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_res_config_settings__ks_email_id +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.res_config_settings_inherit_view +msgid "Email ID" +msgstr "邮件 ID" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_kpi_mail__name +msgid "Email To:" +msgstr "电子邮件至:" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__multi_layouts +#, fuzzy +msgid "Enable Multi-Dashboard Layouts" +msgstr "启用多仪表板布局" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_goal_enable msgid "Enable Target" @@ -1008,18 +1574,39 @@ msgstr "启用目标" #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_item_end_date #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "End Date" -msgstr "完工日" +msgstr "结束日期" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_format__global +#, fuzzy msgid "English Format" msgstr "英文格式" +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +#, fuzzy +msgid "Enter Model" +msgstr "输入模型" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_unit msgid "Enter Unit" msgstr "输入单位" +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#, fuzzy, python-format +msgid "Enter the input keywords to render the item" +msgstr "输入输入关键字以呈现项目" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_key_fetch.py:0 +#, fuzzy, python-format +msgid "Error generates with following status %s" +msgstr "生成以下状态%s" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_data_formatting__exact msgid "Exact" @@ -1031,67 +1618,119 @@ msgid "Exact Value" msgstr "精确值" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__data_source__excel +msgid "Excel" +msgstr "Excel" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__excel_bool +#, fuzzy +msgid "Excel Bool" +msgstr "Excel 布尔值" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#, fuzzy, python-format +msgid "Explain with AI" +msgstr "使用 AI 进行解释" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 #, python-format msgid "Export" msgstr "导出" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_export_all_records +#, fuzzy msgid "Export All Records" msgstr "导出所有记录" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 #, python-format msgid "Export Chart" msgstr "导出图表" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Export Dashboard" msgstr "导出仪表板" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #, python-format msgid "Export Item" msgstr "导出项目" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #, python-format msgid "Export List" msgstr "导出列表" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#, fuzzy, python-format msgid "Export to CSV" msgstr "导出CSV" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 #, python-format msgid "Export to Excel" msgstr "导出Excel" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#, python-format +msgid "Failed" +msgstr "失败" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#, python-format +msgid "False" +msgstr "否" + +#. module: ks_dashboard_ninja +#: model:ir.actions.act_window,name:ks_dashboard_ninja.ks_fetch_key +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_fetch_key +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_fetch_key_form_view +#, fuzzy +msgid "Fetch API key" +msgstr "获取 API 密钥" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_fetch_key_form_view +msgid "Fetch Key" +msgstr "获取密钥" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 #, python-format msgid "Fields Required : Name, Model, Icon (Default or Custom Upload), Layout" @@ -1104,14 +1743,19 @@ msgstr "必填字段:名称,模型,图标(默认或自定义上传), msgid "Fields to show in list" msgstr "列表中显示的字段" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__filename +msgid "Filename" +msgstr "文件名" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_fill_temporal msgid "Fill Temporal Value" msgstr "填写时间值" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view #, python-format msgid "Filter" @@ -1124,8 +1768,21 @@ msgid "Filter Label" msgstr "筛选标签" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_flower_view_preview +#, fuzzy +msgid "Flower Preview" +msgstr "花预览" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_flower_view +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_flower_view +#, fuzzy +msgid "Flower View" +msgstr "花景" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml:0 #, python-format msgid "Font Awesome 4.7.0" msgstr "Font Awesome 4.7.0" @@ -1141,15 +1798,35 @@ msgid "Format" msgstr "格式" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_quick_edit_view.xml:0 #, python-format msgid "Full Settings" msgstr "所有设置" #. module: ks_dashboard_ninja -#. openerp-web +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_funnel_chart +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_funnel_chart +msgid "Funnel Chart" +msgstr "漏斗图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_funnel_preview +#, fuzzy +msgid "Funnel Preview" +msgstr "漏斗预览" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_funnel_record_field +#, fuzzy +msgid "Funnel Record Field" +msgstr "漏斗记录字段" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__n_future_starting_now #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__n_future_starting_now #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__n_future_starting_now @@ -1158,8 +1835,10 @@ msgid "Future Starting Now" msgstr "今日起" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__n_futurestarting_tomorrow #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__n_futurestarting_tomorrow #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__n_futurestarting_tomorrow @@ -1167,6 +1846,80 @@ msgstr "今日起" msgid "Future Starting Tomorrow" msgstr "明日起" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, fuzzy, python-format +msgid "Generate Dashboard with AI" +msgstr "使用 AI 生成仪表板" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +#, fuzzy +msgid "Generate Item" +msgstr "生成项目" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.xml:0 +#, python-format +msgid "Generate With AI" +msgstr "使用 AI 生成" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_ai_whole_dashboard_form_view +#, fuzzy +msgid "Generate dashboard with AI" +msgstr "使用 AI 生成仪表板" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#, fuzzy, python-format +msgid "Generate items with AI" +msgstr "使用 AI 生成项目" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, fuzzy, python-format +msgid "Generate items with AI button" +msgstr "使用 AI 按钮生成项目" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +#, fuzzy +msgid "Generate with" +msgstr "生成方式" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +#, python-format +msgid "Generate with AI" +msgstr "使用 AI 生成" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__ks_api_key +#, fuzzy +msgid "Generated AI API Key" +msgstr "生成的 AI API 密钥" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.res_config_settings_inherit_view +msgid "Get API key" +msgstr "获取API密钥" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 +#, fuzzy, python-format +msgid "Getting invalid response from AI, please try again" +msgstr "收到来自 AI 的无效响应,请重试" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__sequence msgid "Gives the sequence order when displaying a list of payment terms lines." @@ -1193,6 +1946,8 @@ msgid "Group Access" msgstr "组访问权限" #. module: ks_dashboard_ninja +#: model:ir.actions.act_window,name:ks_dashboard_ninja.action_group_by +#: model:ir.actions.act_window,name:ks_dashboard_ninja.csv_action_group_by #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_relation_groupby #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view @@ -1207,12 +1962,20 @@ msgid "Group By Date" msgstr "按日期分组" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_group_by_lines +#, fuzzy +msgid "Group By Lines" +msgstr "按行分组" + +#. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 #, python-format msgid "Groupby Field aggregation" msgstr "按字段分组" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 #, python-format msgid "Groupby field: {} cannot be aggregated by {}" @@ -1238,20 +2001,36 @@ msgstr "页眉" msgid "Header Background Color" msgstr "页眉背景颜色" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, fuzzy, python-format +msgid "Here are your generated Items, kindly select to add them in your current dashboard" +msgstr "以下是您生成的项目,请选择将它们添加到您当前的仪表板中" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_hide_legend +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_radial_legend msgid "Hide all legend from the chart item" msgstr "隐藏所有图表项图例" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_9 +msgid "Horizontal Bar" +msgstr "单栏" + +#. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_horizontalbar_chart #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_horizontalbar_chart -#, python-format msgid "Horizontal Bar Chart" msgstr "水平条形图" +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_22 +#, fuzzy +msgid "Horizontal Bar(sub-group)" +msgstr "单杠(子组)" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__hour #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_sub_groupby__hour @@ -1260,14 +2039,27 @@ msgid "Hour" msgstr "小时" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_delete_wizard__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_duplicate_wizard__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_kpi_mail__id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__id @@ -1291,18 +2083,26 @@ msgid "Icon Option" msgstr "图标选项" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_import_list_view_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#: model:ir.actions.act_window,name:ks_dashboard_ninja.ks_import_dashboard_action +#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_import +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_import_dashboard_form_view #, python-format msgid "Import Dashboard" msgstr "导入仪表板" #. module: ks_dashboard_ninja -#. openerp-web +#: model:ir.ui.menu,name:ks_dashboard_ninja.ks_import_dashboard_menu +msgid "Import Dashboards" +msgstr "导入仪表盘" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Import Item" -msgstr "导入项目" +#, fuzzy, python-format +msgid "Import-item" +msgstr "导入项" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_compare_period @@ -1317,16 +2117,42 @@ msgstr "印度" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_format__indian +#, fuzzy msgid "Indian Format" msgstr "印度格式" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#, python-format +msgid "Info" +msgstr "信息" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Invalid Date" msgstr "无效的日期范围" +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 +#, python-format +msgid "Invalid file!" +msgstr "无效的文件!" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_is_cumulative +#, fuzzy +msgid "Is Cumulative" +msgstr "是累积的" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__ks_active msgid "Is Selected" @@ -1344,15 +2170,24 @@ msgid "Item Configurations" msgstr "项目配置" #. module: ks_dashboard_ninja -#. openerp-web +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_info +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +msgid "Item Description" +msgstr "项目描述" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Item Duplicated" msgstr "项目复制" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Item Moved" msgstr "项目移动" @@ -1363,20 +2198,43 @@ msgid "Item Type" msgstr "项目类型" #. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_update_items_data -msgid "Item Update Interval" -msgstr "项目更新间隔" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view -msgid "Item Update Interval.." -msgstr "项目更新间隔.." - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_kpi +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #, python-format +msgid "Item description" +msgstr "项目描述" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 +#, python-format +msgid "Items added" +msgstr "项目已添加" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 +#, fuzzy, python-format +msgid "Items are added to ." +msgstr "项目已添加到 。" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#, fuzzy, python-format +msgid "Items didn't render because AI provides invalid response for this model.Please try again" +msgstr "项未呈现,因为 AI 为此模型提供无效响应。请重试" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#: code:addons/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py:0 +#, fuzzy, python-format +msgid "Items didn't render, please try again!" +msgstr "项目未呈现,请重试!" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_kpi msgid "KPI" msgstr "KPI" @@ -1387,13 +2245,15 @@ msgstr "KPI 数据" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_extension_2 +#, fuzzy msgid "KPI Domain Extension" -msgstr "KPI 域名后缀" +msgstr "KPI 域扩展" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_compare_period_2 +#, fuzzy msgid "KPI Include Period" -msgstr "关键绩效指标包括期间" +msgstr "KPI 包含期间" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_count_2 @@ -1402,14 +2262,51 @@ msgstr "KPI 记录计数" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_year_period_2 +#, fuzzy msgid "KPI Same Period Previous Years" -msgstr "关键绩效指标 往年同期" +msgstr "KPI 前几年同期" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_kpi_type__layout_1 msgid "KPI With Target" msgstr "目标KPI" +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_arti_int__ks_type__ks_keyword +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view +msgid "Keywords" +msgstr "关键词" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_18 +#, fuzzy +msgid "Kpi ( Number)" +msgstr "Kpi ( 数字)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_17 +#, fuzzy +msgid "Kpi ( Percentage)" +msgstr "KPI ( 百分比)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_27 +#, fuzzy +msgid "Kpi (previous)" +msgstr "Kpi(以前)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_19 +#, fuzzy +msgid "Kpi (sum)" +msgstr "Kpi (总和)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_26 +#, fuzzy +msgid "Kpi 26(Average)" +msgstr "KPI 26(平均)" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_comparison msgid "Kpi Data Type" @@ -1460,6 +2357,12 @@ msgstr "Kpi 模型名称" msgid "Kpi Preview" msgstr "Kpi 预览" +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_16 +#, fuzzy +msgid "Kpi Ratio" +msgstr "Kpi 比率" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_field_2 msgid "Kpi Record Field" @@ -1475,6 +2378,30 @@ msgstr "Kpi 记录类型" msgid "Kpi Start Date" msgstr "Kpi 开始日期" +#. module: ks_dashboard_ninja +#: model:ir.actions.server,name:ks_dashboard_ninja.ir_cron_send_target_email_ir_actions_server +#, fuzzy +msgid "Kpi mail cron" +msgstr "Kpi mail cron" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__ks_type +#, fuzzy +msgid "Ks AI Type" +msgstr "Ks AI 型" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_ai_explain_dash +#, fuzzy +msgid "Ks Ai Explain Dash" +msgstr "Ks Ai 解释 Dash" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_bounds +#, fuzzy +msgid "Ks Bounds" +msgstr "Ks 边界" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_groupby_type msgid "Ks Chart Groupby Type" @@ -1487,6 +2414,7 @@ msgstr "图表子级分组类型" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_child_dashboard_ids +#, fuzzy msgid "Ks Child Dashboard" msgstr "Ks 儿童仪表板" @@ -1505,21 +2433,53 @@ msgstr "仪表板菜单" msgid "Ks Dashboard State" msgstr "仪表板状态" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_db_name +#, fuzzy +msgid "Ks Db Name" +msgstr "Ks 数据库名称" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_db_password +#, fuzzy +msgid "Ks Db Password" +msgstr "Ks 数据库密码" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_db_user +#, fuzzy +msgid "Ks Db User" +msgstr "Ks 数据库用户" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dn_header_lines +#, fuzzy msgid "Ks Dn Header Lines" -msgstr "Ks Dn 标题行" +msgstr "Ks dn 标题行" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__ks_dn_item_id +#, fuzzy msgid "Ks Dn Item" -msgstr "Ks Dn 项目" +msgstr "杀人头 dn 物品" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_gridstack_config msgid "Ks Gridstack Config" msgstr "网格堆栈配置" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_host +#, fuzzy +msgid "Ks Host" +msgstr "Ks 主机" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_is_external_db +#, fuzzy +msgid "Ks Is External Db" +msgstr "ks 是外部数据库" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_isDateFilterApplied msgid "Ks Isdatefilterapplied" @@ -1535,24 +2495,52 @@ msgstr "项目行动领域类型" msgid "Ks Item Count" msgstr "项目计数" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__ks_input_keywords +#, fuzzy +msgid "Ks Keywords" +msgstr "Ks 关键词" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_many2many_field_ordering msgid "Ks Many2Many Field Ordering" msgstr "KS多对多字段排序" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__ks_model_show +#, fuzzy +msgid "Ks Model Show" +msgstr "KS模型展示" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_partners_map +#, fuzzy +msgid "Ks Partners Map" +msgstr "Ks 合作伙伴地图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_port +#, fuzzy +msgid "Ks Port" +msgstr "KS 端口" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__ks_to_do_description_lines +#, fuzzy msgid "Ks To Do Description Lines" -msgstr "Ks 待办事项说明行" +msgstr "KS 待办事项描述行" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__ks_to_do_header_id +#, fuzzy msgid "Ks To Do Header" -msgstr "Ks 待办事项标题" +msgstr "Ks To Do 标头" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__l_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__l_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__l_month @@ -1561,8 +2549,10 @@ msgid "Last 30 days" msgstr "最近30天" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__l_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__l_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__l_year @@ -1571,18 +2561,22 @@ msgid "Last 365 days" msgstr "最近365天" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__l_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__l_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__l_week -#, python-format +#, fuzzy, python-format msgid "Last 7 days" -msgstr "最近 7 天" +msgstr "最近7天" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__l_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__l_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__l_quarter @@ -1591,8 +2585,10 @@ msgid "Last 90 days" msgstr "最近90天" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__ls_day #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__ls_day #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__ls_day @@ -1601,23 +2597,10 @@ msgid "Last Day" msgstr "最后一天" #. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description____last_update -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers____last_update -msgid "Last Modified on" -msgstr "最后修改日期" - -#. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__ls_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__ls_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__ls_month @@ -1626,8 +2609,10 @@ msgid "Last Month" msgstr "上个月" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__ls_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__ls_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__ls_quarter @@ -1636,29 +2621,55 @@ msgid "Last Quarter" msgstr "上个季度" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_delete_wizard__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_duplicate_wizard__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_kpi_mail__write_uid +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__write_uid #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__write_uid msgid "Last Updated by" -msgstr "最后修改人" +msgstr "最后更新人" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_delete_wizard__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_duplicate_wizard__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_kpi_mail__write_date +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__write_date #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__write_date @@ -1666,8 +2677,10 @@ msgid "Last Updated on" msgstr "最后更新时间" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__ls_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__ls_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__ls_week @@ -1676,8 +2689,10 @@ msgid "Last Week" msgstr "上周" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__ls_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__ls_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__ls_year @@ -1692,37 +2707,42 @@ msgstr "布局" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout1 +#, fuzzy msgid "Layout 1" -msgstr "布局 1" +msgstr "布局1" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout2 +#, fuzzy msgid "Layout 2" -msgstr "布局 2" +msgstr "布局2" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout3 +#, fuzzy msgid "Layout 3" -msgstr "布局 3" +msgstr "布局3" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout4 +#, fuzzy msgid "Layout 4" -msgstr "布局 4" +msgstr "布局4" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout5 +#, fuzzy msgid "Layout 5" -msgstr "布局 5" +msgstr "布局5" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout6 msgid "Layout 6" -msgstr "布局 6" +msgstr "布局6" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 #, python-format msgid "Layout Coming Soon" msgstr "布局即将推出" @@ -1733,14 +2753,18 @@ msgid "Layout..." msgstr "布局..." #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_line_chart #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_line_chart -#, python-format +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_6 msgid "Line Chart" msgstr "折线图" +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_24 +#, fuzzy +msgid "Line Chart with values" +msgstr "带值的折线图" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_measure_field_2 #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view @@ -1749,11 +2773,8 @@ msgid "Line Measure" msgstr "拆线维度" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_list_view #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_list_view -#, python-format msgid "List View" msgstr "列表视图" @@ -1777,16 +2798,64 @@ msgstr "列表预览" msgid "List View Type" msgstr "列表视图类型" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_map_chart_relation_groupby +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "Map Group By" +msgstr "映射分组依据" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_map_preview +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +msgid "Map Preview" +msgstr "地图预览" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_map_record_field +#, fuzzy +msgid "Map Record Field" +msgstr "映射记录字段" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_map_view +msgid "Map View" +msgstr "地图视图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__material +#, fuzzy +msgid "Material" +msgstr "生产超料单" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_unit msgid "Maximum limit 5 characters, for ex: km, m" msgstr "最大限制5个字符,例如:km, m" +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view +msgid "Measure" +msgstr "测量" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_measure_field msgid "Measure 1" msgstr "维度1" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_scatter_measure_x_id +#, fuzzy +msgid "Measure X" +msgstr "度量 X" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_scatter_measure_y_id +#, fuzzy +msgid "Measure Y" +msgstr "测量 Y" + #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view @@ -1794,8 +2863,10 @@ msgid "Measures" msgstr "度量" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__ks_menu_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_menu_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__ks_dashboard_menu_name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__ks_menu_name msgid "Menu Name" msgstr "菜单名称" @@ -1812,17 +2883,35 @@ msgid "Minute" msgstr "分钟" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__ks_model_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__ks_import_model_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__ks_import_model #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__ks_model_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_model_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_model_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_model_id +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_arti_int__ks_type__ks_model #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_ai_whole_dashboard_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_ai_form_view msgid "Model" msgstr "模型" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__model_bool +#, fuzzy +msgid "Model Bool" +msgstr "Model Bool" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_arti_int__ks_import_model_id +msgid "Model ID" +msgstr "模型 ID" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_model_name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_model_name +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Model Name" msgstr "模型名称" @@ -1843,23 +2932,44 @@ msgstr "币种" msgid "Month" msgstr "月" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__td_month +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__td_month +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__td_month +#, python-format +msgid "Month to Date" +msgstr "本月至今" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__month_year +#, fuzzy msgid "Month-Year" msgstr "月-年" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__moonrise +#, fuzzy +msgid "Moonrise" +msgstr "月出" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 #, python-format msgid "More Info" msgstr "更多信息" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #: model:ir.actions.server,name:ks_dashboard_ninja.ks_move_dashboard #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_ninja_dashboard_item_action__ks_action__move #, python-format @@ -1867,33 +2977,63 @@ msgid "Move" msgstr "移动" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #, python-format msgid "Move/Duplicate" msgstr "移动/复制" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__ks_multiplier_value +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_multiplier +msgid "Multiplier" +msgstr "乘数" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_item_multiplier__ks_multiplier_fields +#, fuzzy +msgid "Multiplier Field" +msgstr "乘数字段" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_multiplier_lines +msgid "Multiplier Lines" +msgstr "乘法折线图" + #. module: ks_dashboard_ninja #: model:ir.actions.client,name:ks_dashboard_ninja.board_dashboard_action_window -#: model:ir.ui.menu,name:ks_dashboard_ninja.board_menu_root #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_tree msgid "My Dashboard" msgstr "我的仪表板" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__name +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__name #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__name +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Name" msgstr "名称" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__name_seq +#, fuzzy +msgid "Name Seq" +msgstr "名称 Seq" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_company_id +#, fuzzy msgid "Name of the company for which analytics will be displayed in the dashboard. " -msgstr "将在仪表板中显示分析结果的公司名称。" +msgstr "将在功能板中显示其分析的公司名称。" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view @@ -1901,27 +3041,31 @@ msgid "Name..." msgstr "名称..." #. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__neon -msgid "Neon" -msgstr "霓虹灯" +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, python-format +msgid "New Dashboard" +msgstr "新仪表盘" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js:0 #, python-format msgid "New Task" msgstr "新任务" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#, fuzzy, python-format msgid "Next" -msgstr "下一页" +msgstr "下一个" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__n_day #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__n_day #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__n_day @@ -1930,8 +3074,10 @@ msgid "Next Day" msgstr "明天" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__n_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__n_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__n_month @@ -1940,8 +3086,10 @@ msgid "Next Month" msgstr "下个月" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__n_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__n_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__n_quarter @@ -1950,8 +3098,10 @@ msgid "Next Quarter" msgstr "下个季度" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__n_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__n_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__n_week @@ -1960,8 +3110,10 @@ msgid "Next Week" msgstr "下周" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__n_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__n_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__n_year @@ -1970,82 +3122,94 @@ msgid "Next Year" msgstr "明年" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_new_list_view.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml:0 #, python-format msgid "No Data Present" msgstr "没有可呈现的数据" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.xml:0 #, python-format msgid "No Section Available." msgstr "没有部分可用。" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#, python-format +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.xml:0 +#, fuzzy, python-format msgid "No Tasks Available" -msgstr "无任务可用" +msgstr "无可用任务" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_comparison__none #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__l_none #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__l_none -#, python-format msgid "None" msgstr "无" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.xml:0 #, python-format msgid "Note :" msgstr "备注:" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml:0 #, python-format msgid "Note:" msgstr "注意:" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 -#, python-format +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_target_view__number msgid "Number" -msgstr "数量" +msgstr "编号" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_format +#, fuzzy msgid "Number System" msgstr "数字系统" +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__data_source__odoo +msgid "Odoo" +msgstr "Odoo" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_pagination_limit +#, fuzzy msgid "Pagination Limit" msgstr "分页限制" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format +#, fuzzy, python-format msgid "Pagination limit value cannot be Negative or Zero" -msgstr "分页限制值不能为负或零" +msgstr "分页限制值不能为负数或零" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Past Excluding Today" msgstr "过去(不包括今天)" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__ls_past_until_now #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__ls_past_until_now #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__ls_past_until_now @@ -2054,70 +3218,131 @@ msgid "Past Till Now" msgstr "截止到现在" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 -#, python-format +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_label_type__percent +msgid "Percent" +msgstr "百分比" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_comparison__percentage msgid "Percentage" msgstr "百分比" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_pie_chart #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_pie_chart -#, python-format +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_14 +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_7 msgid "Pie Chart" msgstr "饼图" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 #, python-format msgid "Please Install the Module which contains the following Model : %s ks_model_id" msgstr "请安装包含以下模组的模块 : %s ks_model_id" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format +#, fuzzy, python-format msgid "Please chose any Data Type!" msgstr "请选择任何数据类型!" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#: code:addons/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py:0 +#, fuzzy, python-format +msgid "Please enter URL and API Key in General Settings" +msgstr "请在常规设置中输入 URL 和 API 密钥" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/res_settings.py:0 +#, fuzzy, python-format +msgid "Please enter URL and Email ID" +msgstr "请输入 URL 和电子邮件 ID" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/res_settings.py:0 +#, fuzzy, python-format +msgid "Please enter correct URL" +msgstr "请输入正确的 URL" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Please enter start date and end date" msgstr "请设置开始日期和结束日期" #. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/lib/ks_date_filter_selections.py:0 -#, python-format +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#: code:addons/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py:0 +#, fuzzy, python-format +msgid "Please enter the Model" +msgstr "请输入型号" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#, fuzzy, python-format +msgid "Please put API key and URL" +msgstr "请输入 API 密钥和 URL" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml:0 +#, fuzzy, python-format +msgid "Please run the appropriate Query" +msgstr "请运行相应的 Query" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py:0 +#, fuzzy, python-format msgid "Please set the local timezone." msgstr "请设置当地时区。" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#, python-format +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml:0 +#, fuzzy, python-format msgid "" "Please use Font Awesome 4.7.0 icons only. E.g. 'fa-bell' or 'bell'.\n" -" For more information visit" +" For more information visit" msgstr "" -"请仅使用Font Awesome 4.7.0图标。例如。 “ fa-bell”或“ bell”。\n" -" 欲了解更多信息,请访问" +"请仅使用 Font Awesome 4.7.0 图标。例如,'fa-bell' 或 'bell'。\n" +" 欲了解更多信息,请访问" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#, fuzzy, python-format +msgid "Plese make few items to explain with AI" +msgstr "请做一些项目来用 AI 解释" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_10 +msgid "Polar Area" +msgstr "柱状图" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_polararea_chart #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_polararea_chart -#, python-format msgid "Polar Area Chart" msgstr "极地面积图" #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_form +#, fuzzy msgid "Pre Defined Filters" -msgstr "预设过滤器" +msgstr "预定义过滤器" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board_template__ks_template_type__ks_default @@ -2127,30 +3352,41 @@ msgstr "预定义" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_preview #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_create_dashboard_wizard_form msgid "Preview" msgstr "预览" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 #, python-format msgid "Previous" msgstr "上一个" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Print" msgstr "打印" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 -#, python-format +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_target_view__progress_bar msgid "Progress Bar" msgstr "进度条" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_multiplier +#, fuzzy +msgid "Provides the multiplication of record value" +msgstr "提供记录值的乘法" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_multiplier_active +#, fuzzy +msgid "Provides the visibility of multiplier field" +msgstr "提供 multiplier 字段的可见性" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_sub_groupby__quarter @@ -2159,18 +3395,51 @@ msgid "Quarter" msgstr "季度" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__td_quarter +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__td_quarter +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__td_quarter +#, python-format +msgid "Quarter to Date" +msgstr "本季度至今" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 #, python-format msgid "Quick Customize" msgstr "快速定制" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 -#, python-format +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_radar_view +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_radar_view +#, fuzzy +msgid "Radar View" +msgstr "雷达视图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_radialbar_chart +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_radialbar_chart +#, fuzzy +msgid "Radial Bar Chart" +msgstr "径向条形图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_radial_preview +#, fuzzy +msgid "Radial Preview" +msgstr "径向预览" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_comparison__ratio msgid "Ratio" msgstr "比率" @@ -2198,6 +3467,7 @@ msgstr "记录限制" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_data_limit_visibility +#, fuzzy msgid "Record Limit Data Visibility" msgstr "记录限制数据可见性" @@ -2215,22 +3485,25 @@ msgstr "记录值" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_actions +#, fuzzy msgid "Redirects you to the selected view. " msgstr "将您重定向到所选视图。" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 #, python-format msgid "Remove" msgstr "删除" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.xml:0 #, python-format msgid "Remove Item" msgstr "删除项目" @@ -2242,65 +3515,100 @@ msgid "Same Period Previous Years" msgstr "去年同一时期" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: code:addons/ks_dashboard_ninja/static/src/xml/ks_quick_edit_view.xml:0 +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_create_dashboard_wizard_form #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_action +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_import_dashboard_form_view #, python-format msgid "Save" msgstr "保存" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Save Changes" msgstr "保存更改" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format +#, fuzzy, python-format msgid "Save Changes as a New Layout" -msgstr "将更改保存为新布局" +msgstr "将更改另存为新布局" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 #, python-format msgid "Save as Image" msgstr "保存为图像" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format +#, fuzzy, python-format msgid "Save as New Layout" -msgstr "保存为新布局" +msgstr "另存为新布局" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 #, python-format msgid "Save as PDF" msgstr "保存为PDF" +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_scatter_chart +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_chart_type__ks_scatter_chart +msgid "Scatter Chart" +msgstr "散点图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_is_scatter_group +#, fuzzy +msgid "Scatter Group By" +msgstr "散点分组依据" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_scatter_field_id +#, fuzzy +msgid "Scatter Points" +msgstr "散点" + #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_item_search_view msgid "Search Items" msgstr "搜索项目" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/domainfix.js:0 +#, python-format +msgid "Search More..." +msgstr "搜索更多..." + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml:0 #, python-format msgid "Search fa-icon.." msgstr "搜索 fa-icon.." #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#, python-format +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.xml:0 +#, fuzzy, python-format +msgid "Search items with AI..." +msgstr "使用 AI 搜索项目..." + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml:0 +#, fuzzy, python-format msgid "Search through site content" msgstr "搜索网站内容" @@ -2311,22 +3619,20 @@ msgid "Section" msgstr "部分" #. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Sections" -msgstr "部分" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#, python-format +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml:0 +#, fuzzy, python-format msgid "Select" msgstr "选择" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__ks_dashboard_ninja_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__ks_dashboard_ninja_id #, python-format @@ -2339,106 +3645,173 @@ msgid "Select Dashboards" msgstr "选择仪表板" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#, python-format -msgid "Select Icon" -msgstr "选择图标" +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml:0 +#, fuzzy, python-format +msgid "Select Fields and Group By to show in list view" +msgstr "选择 Fields(字段)和 Group By(分组依据)以在列表视图中显示" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml:0 +#, fuzzy, python-format +msgid "Select Fields to show in list view" +msgstr "选择要在列表视图中显示的字段" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml:0 +#, fuzzy, python-format +msgid "Select Group by Date to show list data." +msgstr "选择 Group by Date (按日期分组) 以显示列表数据。" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.xml:0 #, python-format msgid "Select Icons" msgstr "选择图标" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, python-format +msgid "Select None" +msgstr "全部不选" + #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_unit_selection msgid "Select Unit Type" msgstr "选择单位类型" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml:0 +#, fuzzy, python-format +msgid "Select a model first" +msgstr "首先选择模型" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml:0 +#, fuzzy, python-format +msgid "Select a record field" +msgstr "选择记录字段" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml:0 +#, fuzzy, python-format +msgid "Select a reocrd field" +msgstr "选择 reocrd 域" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, python-format +msgid "Select all" +msgstr "全选" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_selection +#, fuzzy msgid "Select interval of the records to be displayed. " -msgstr "选择要显示的记录时间间隔。" +msgstr "选择要显示的记录的间隔。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_item_theme +#, fuzzy msgid "Select the color theme for the display. " -msgstr "选择显示屏的颜色主题。" +msgstr "选择显示的颜色主题。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_type +#, fuzzy msgid "Select the desired list view type. " msgstr "选择所需的列表视图类型。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_sort_by_field +#, fuzzy msgid "Select the desired sorting preference. " -msgstr "选择所需的排序偏好。" +msgstr "选择所需的排序首选项。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_item_color +#, fuzzy msgid "Select the display preference. " -msgstr "选择显示偏好。" +msgstr "选择显示首选项。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_field +#, fuzzy msgid "Select the field for which Date Filter should be applicable." -msgstr "选择适用日期筛选器的字段。" +msgstr "选择日期筛选器应适用的字段。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_font_color +#, fuzzy msgid "Select the font color. " msgstr "选择字体颜色。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_default_icon #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_default_icon_color +#, fuzzy msgid "Select the icon to be displayed. " msgstr "选择要显示的图标。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_item_type +#, fuzzy msgid "Select the required type of dashboard to display. " -msgstr "选择要显示的所需仪表盘类型。" +msgstr "选择要显示的所需控制面板类型。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_relation_sub_groupby +#, fuzzy msgid "Select the second level of grouping. " msgstr "选择第二级分组。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_calculation_type +#, fuzzy msgid "Select the type of calculation you want to perform on the data." -msgstr "选择要对数据进行计算的类型。" +msgstr "选择要对数据执行的计算类型。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_unit_selection +#, fuzzy msgid "Select the unit to be assigned to the value. " -msgstr "选择要分配给数值的单位。" +msgstr "选择要分配给值的单位。" #. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_auto_update_type -msgid "Select the update type." -msgstr "选择更新类型。" - -#. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Selected item is duplicated to ." msgstr "选择项目复制到." #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Selected item is moved to ." msgstr "选择项目移动到 ." #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 +#, fuzzy, python-format +msgid "Selected model is not supported for Map View." +msgstr "Map View 不支持所选模型。" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_domain_fix.js:0 #, python-format msgid "Selected records" @@ -2446,31 +3819,46 @@ msgstr "已选记录" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_semi_circle_chart +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Semi Circle Chart" msgstr "半圆图" +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_21 +#, fuzzy +msgid "Semi Circle Pie Chart" +msgstr "半圆饼图" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_send_mail +msgid "Send Mail" +msgstr "发送邮件" + #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_defined_filters +#, fuzzy msgid "Separator Name (eg. Order States, Deadlines)" -msgstr "分隔符名称(如订购国、截止日期)" +msgstr "分隔符名称(例如。订单状态、截止日期)" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__sequence #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__sequence +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__ks_sequence msgid "Sequence" msgstr "序列" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Set Current Layout" -msgstr "设置当前布局" +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__name_seq +#, fuzzy +msgid "Sequential Queue ID" +msgstr "顺序队列 ID" #. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Set Update Interval" -msgstr "设置更新间隔" +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, fuzzy, python-format +msgid "Set Current Layout" +msgstr "Set Current Layout(设置当前布局)" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_unit @@ -2482,6 +3870,12 @@ msgstr "显示自定义单位" msgid "Show Data Value" msgstr "显示数据值" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_label_type +#, fuzzy +msgid "Show Data Value Type" +msgstr "显示数据值类型" + #. module: ks_dashboard_ninja #: model:res.groups,name:ks_dashboard_ninja.ks_dashboard_ninja_group_manager msgid "Show Full Dashboard Features" @@ -2493,9 +3887,10 @@ msgid "Show Legend" msgstr "显示图例" #. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_show_live_pop_up -msgid "Show Live Update Pop Up" -msgstr "显示实时更新弹出窗口" +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_radial_legend +#, fuzzy +msgid "Show Radial Legend" +msgstr "显示径向图例" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_show_records @@ -2508,19 +3903,32 @@ msgid "Show Target As Line" msgstr "显示目标线" #. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_duplicate_wizard__ks_top_menu_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_ai_dashboard__ks_top_menu_id #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_top_menu_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__ks_top_menu_id +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_wizard__ks_top_menu_id +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_import_dashboard_form_view msgid "Show Under Menu" msgstr "显示在顶层菜单" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_fetch_key__ks_show_api_key +#, fuzzy +msgid "Show key" +msgstr "显示键" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_standard_goal_value +#, fuzzy msgid "Show the set target" -msgstr "显示既定目标" +msgstr "显示设置的目标" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_goal_enable +#, fuzzy msgid "Show the set target." -msgstr "显示既定目标。" +msgstr "显示设置的目标。" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_menu_sequence @@ -2528,13 +3936,21 @@ msgid "Smallest sequence give high priority and Highest sequence give low priori msgstr "序列号越小,优先级越高;序列越大,优先级越低" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#, python-format -msgid "Some Items can not be imported Need Dashboard Ninja pro " -msgstr "有些项目不能导入,需要高级版仪表盘" +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py:0 +#, fuzzy, python-format +msgid "Some problem in audio generation." +msgstr "音频生成出现问题。" #. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/res_settings.py:0 +#, fuzzy, python-format +msgid "Some problem in sending request.Please contact at sales@ksolves.com" +msgstr "发送请求时出现问题。请联系 sales@ksolves.com" + +#. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_filters.py:0 #, python-format msgid "Something went wrong . Possibly it is due to wrong input type for domain" @@ -2552,8 +3968,16 @@ msgstr "字段排序" msgid "Sort Order" msgstr "排序" +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_dn_to_do_item.py:0 +#, fuzzy, python-format +msgid "Special characters are not allowed only string and digits allow for section header" +msgstr "不允许使用特殊字符,只有字符串和数字允许使用部分标题" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_bar_chart_stacked +#, fuzzy msgid "Stack the columns of the same record. " msgstr "堆叠同一记录的列。" @@ -2576,39 +4000,66 @@ msgid "Start Date" msgstr "开始日期" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#, python-format +#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 +#, fuzzy, python-format msgid "Start date must be less than end date" msgstr "开始日期必须小于结束日期" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #, python-format msgid "Start date should be less than end date" msgstr "开始日期应小于结束日期" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_stop_mail_cron +#, fuzzy +msgid "Stop mail cron" +msgstr "停止邮件 cron" + #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Sub Group By Date" msgstr "日期子级分组" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 #, python-format msgid "Sub Groupby field: {} cannot be aggregated by {}" msgstr "子级分组字段: {} 不能按 {} 聚合" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/res_settings.py:0 +#, python-format +msgid "Success" +msgstr "成功" + +#. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_data_count_type__sum +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_comparison__sum #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_record_count_type_2__sum #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_record_count_type__sum -#, python-format msgid "Sum" msgstr "总计" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, fuzzy, python-format +msgid "Switch to Default Dashboard" +msgstr "切换到默认控制面板" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +msgid "Sync Data" +msgstr "更新日期" + #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Target" @@ -2619,6 +4070,13 @@ msgstr "目标" msgid "Target Lines" msgstr "目标明细" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.xml:0 +#, python-format +msgid "Task" +msgstr "任务" + #. module: ks_dashboard_ninja #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Task Lines" @@ -2636,6 +4094,7 @@ msgstr "用户体验技术领域。" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_template_type +#, fuzzy msgid "Template Format" msgstr "模板格式" @@ -2644,10 +4103,20 @@ msgstr "模板格式" msgid "Template Type" msgstr "模板类型" +#. module: ks_dashboard_ninja +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_country_code +msgid "" +"The ISO country code in two chars. \n" +"You can use this field for quick search." +msgstr "" +"两个字符的 ISO 国家代码。\n" +"您可以使用该字段来快速查询。" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__name +#, fuzzy msgid "The item will be represented by this unique name." -msgstr "项目将由这个唯一的名称表示。" +msgstr "该项目将由此唯一名称表示。" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_item_theme @@ -2660,8 +4129,10 @@ msgid "This Action will be Performed at the end of Drill Down Action" msgstr "此操作将在向下分解操作结束时执行" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__t_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__t_month #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__t_month @@ -2670,8 +4141,10 @@ msgid "This Month" msgstr "本月" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__t_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__t_quarter #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__t_quarter @@ -2680,8 +4153,10 @@ msgid "This Quarter" msgstr "本季度" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__t_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__t_week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__t_week @@ -2690,8 +4165,10 @@ msgid "This Week" msgstr "本周" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__t_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__t_year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__t_year @@ -2712,44 +4189,86 @@ msgstr "" " 默认记录视图" #. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 #, python-format msgid "This file is not supported" msgstr "不支持此文件" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_tile -#, python-format +#, fuzzy msgid "Tile" -msgstr "瓦片" +msgstr "平铺" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_1 +#, fuzzy +msgid "Tile (layout 1)" +msgstr "平铺(布局 1)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_3 +#, fuzzy +msgid "Tile (layout 2)" +msgstr "平铺(布局 2)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_2 +#, fuzzy +msgid "Tile (layout 3)" +msgstr "平铺(布局 3)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_12 +#, fuzzy +msgid "Tile (layout 4)" +msgstr "平铺(布局 4)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_4 +#, fuzzy +msgid "Tile (layout 5)" +msgstr "平铺(布局 5)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_13 +#, fuzzy +msgid "Tile (layout 6)" +msgstr "平铺(布局 6)" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_format +#, fuzzy msgid "To Change the number format showing in chart to given option" msgstr "将图表中显示的数字格式更改为给定选项" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_dashboard_item_type__ks_to_do -#, python-format msgid "To Do" msgstr "待办" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_to_do_data +#, fuzzy msgid "To Do Data in JSon" -msgstr "JSon 中的待办事项数据" +msgstr "在 JSon 中执行数据" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_to_do_preview +#, fuzzy msgid "To Do Preview" msgstr "待办事项预览" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, fuzzy, python-format +msgid "To Generate items with AI, use" +msgstr "要使用 AI 生成项目,请使用" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "To add dashboard item, use" @@ -2757,12 +4276,15 @@ msgstr "要添加仪表板项目,请使用" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_data_limit_visibility +#, fuzzy msgid "To enable the record data limit field" msgstr "启用记录数据限制字段" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 #: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__l_day #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__l_day #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__l_day @@ -2772,18 +4294,45 @@ msgstr "今天" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_button_color +#, fuzzy msgid "Top Button Color" msgstr "顶部按钮颜色" #. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/color_picker/ks_color_picker.xml:0 +#, fuzzy, python-format +msgid "Transparency :" +msgstr "透明度:" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml:0 +#, python-format +msgid "True" +msgstr "是" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_group_by__ttype +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_csv_new__ttype +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_group_by__ttype +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_new__ttype #: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view msgid "Type" msgstr "类型" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_count_type +#, fuzzy msgid "Type of record how record will show as count,sum and average of the record" -msgstr "记录类型 如何显示记录的计数、总和和平均值" +msgstr "记录类型 记录如何显示为记录的 count、sum 和 average" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_res_config_settings__url +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.res_config_settings_inherit_view +#, fuzzy +msgid "URL" +msgstr "URL" #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_list_view_type__ungrouped @@ -2791,39 +4340,64 @@ msgid "Un-Grouped" msgstr "未分组" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 #, python-format msgid "Unarchive" msgstr "取消归档" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/domainfix.js:0 +#, python-format +msgid "Unnamed" +msgstr "未命名" + #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_set_interval msgid "Update Interval for new items only" msgstr "更新新项目的时间间隔" #. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_auto_update_type__ks_live_update -msgid "Update at every instance." -msgstr "随时更新。" +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_csv_field +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +msgid "Upload CSV File" +msgstr "上载 CSV 文件" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_import__ks_import_dashboard +#, fuzzy +msgid "Upload Dashboard" +msgstr "上传仪表板" + +#. module: ks_dashboard_ninja +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_import_dashboard_form_view +msgid "Upload Dashboard Json" +msgstr "上传仪表板Json格式内容" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__upload_excel +#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view +#, fuzzy +msgid "Upload Excel File" +msgstr "上传 Excel 文件" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_widget_toggle.xml:0 #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_icon -#, python-format msgid "Upload Icon" msgstr "上传图标" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.xml:0 #, python-format msgid "Uploading..." msgstr "上传中..." #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__ks_goal_value +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_label_type__value +#, fuzzy msgid "Value" msgstr "值" @@ -2837,11 +4411,6 @@ msgstr "查看" msgid "View Items" msgstr "查看项目" -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__warm -msgid "Warm" -msgstr "暖色" - #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__week #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_sub_groupby__week @@ -2849,25 +4418,161 @@ msgstr "暖色" msgid "Week" msgstr "周" +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#, fuzzy, python-format +msgid "Week To Date" +msgstr "周至今" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__td_week +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__td_week +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__td_week +msgid "Week to Date" +msgstr "本周结束日期" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#, python-format +msgid "Welcome" +msgstr "欢迎" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_label_type +#, fuzzy +msgid "When \"Show Data Value Type\" selected this field enables to select label type in percent or value" +msgstr "当选择“显示数据值类型”时,此字段可以按百分比或值选择标签类型" + #. module: ks_dashboard_ninja #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_sub_groupby__year #: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_item_action_date_groupby__year msgid "Year" -msgstr "年份" +msgstr "年" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_date_filter_selection__td_year +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection_2__td_year +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__td_year +#, python-format +msgid "Year to Date" +msgstr "年初至今" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 +#, fuzzy, python-format +msgid "You cannot delete any default template" +msgstr "您无法删除任何默认模板" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, fuzzy, python-format +msgid "Your AI dashboard is empty" +msgstr "您的 AI 控制面板为空" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "Your personal dashboard is empty" msgstr "无个人仪表板" #. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_group_by__ttype__char +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_new__ttype__char +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_group_by__ttype__char +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_new__ttype__char +msgid "char" +msgstr "字符型" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_group_by__ttype__date +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_new__ttype__date +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_group_by__ttype__date +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_new__ttype__date +msgid "date" +msgstr "日期" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_group_by__ttype__datetime +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_new__ttype__datetime +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_group_by__ttype__datetime +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_new__ttype__datetime +msgid "datetime" +msgstr "日期时间" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_group_by__ttype__float +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_new__ttype__float +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_group_by__ttype__float +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_new__ttype__float +msgid "float" +msgstr "浮点数" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__grid_corners +#, fuzzy +msgid "grid corners" +msgstr "网格角" + +#. module: ks_dashboard_ninja +#. odoo-python #: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format +#, fuzzy, python-format msgid "if target lines is selected then cannot be set pagination value" -msgstr "如果选择了目标行,则无法设置分页值" +msgstr "如果选择了 Target Lines,则无法设置 Pagination Value" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_item_type_selection/ks_item_type_selection.xml:0 +#, python-format +msgid "image" +msgstr "图片" + +#. module: ks_dashboard_ninja +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_group_by__ttype__integer +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_csv_new__ttype__integer +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_group_by__ttype__integer +#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_new__ttype__integer +msgid "integer" +msgstr "整数" + +#. module: ks_dashboard_ninja +#. odoo-python +#: code:addons/ks_dashboard_ninja/models/res_settings.py:0 +#, fuzzy, python-format +msgid "key already generated.If you need assistance, feel free to contact at sales@ksolves.com" +msgstr "key 中。如果您需要帮助,请随时联系 sales@ksolves.com" + +#. module: ks_dashboard_ninja +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 +#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js:0 +#, fuzzy, python-format +msgid "ks_open_setting" +msgstr "ks_open_setting" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_8 +#, fuzzy +msgid "list view (Un-Grouped)" +msgstr "列表视图 (Un-Grouped)" + +#. module: ks_dashboard_ninja +#: model:ks_dashboard_ninja.item,name:ks_dashboard_ninja.ks_default_item_28 +#, fuzzy +msgid "list view (grouped)" +msgstr "列表视图(分组)" #. module: ks_dashboard_ninja #: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_target_deviation_field @@ -2875,14 +4580,21 @@ msgid "list_field_id" msgstr "list_field_id" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 #, python-format msgid "on top right corner." msgstr "在右上角。" #. module: ks_dashboard_ninja -#. openerp-web +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml:0 +#, fuzzy, python-format +msgid "on top right." +msgstr "在右上角。" + +#. module: ks_dashboard_ninja +#. odoo-javascript #: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 #, python-format msgid "or" @@ -2899,22 +4611,29 @@ msgid "to do headers" msgstr "用作页眉" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml:0 #, python-format msgid "vs Prev" msgstr "VS 上一期间" #. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 +#. odoo-javascript +#: code:addons/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml:0 +#: code:addons/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml:0 #, python-format msgid "vs Target" msgstr "与目标" #. module: ks_dashboard_ninja #: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_export_all_records +#, fuzzy msgid "when click on boolean button, all the records will be downloaded which are present in entire list" -msgstr "点击布尔按钮后,将下载整个列表中的所有记录" +msgstr "单击布尔按钮时,将下载整个列表中的所有记录" + +#. module: ks_dashboard_ninja +#: model:ir.ui.menu,name:ks_dashboard_ninja.board_menu_root +#, fuzzy +msgid "仪表板10" +msgstr "仪表板10" diff --git a/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py b/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py index 32a8eb558..e320bb1ba 100644 --- a/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py +++ b/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py @@ -1,8 +1,11 @@ import json import logging import requests -from odoo import http, api, fields, models, _ +from odoo import http, api, fields, models, _ from odoo.exceptions import ValidationError +from gtts import gTTS +import base64 +import os _logger = logging.getLogger(__name__) @@ -14,9 +17,9 @@ class KsDashboardNInjaAI(models.TransientModel): ks_type = fields.Selection([('ks_model', 'Model'), ('ks_keyword', 'Keywords')], string="Ks AI Type", default='ks_model') - ks_import_model_id = fields.Many2one('ir.model', string='Model', + ks_import_model_id = fields.Many2one('ir.model', string='Model ID', domain="[('access_ids','!=',False),('transient','=',False)," - "('model','not ilike','base_import%'),('model','not ilike','ir.%')," + "('model','not ilike','base_import%'),'|',('model','not ilike','ir.%'),('model','=ilike','_%ir.%')," "('model','not ilike','web_editor.%'),('model','not ilike','web_tour.%')," "('model','!=','mail.thread'),('model','not ilike','ks_dash%'),('model','not ilike','ks_to%')]", help="Data source to fetch and read the data for the creation of dashboard items. ") @@ -48,9 +51,6 @@ class KsDashboardNInjaAI(models.TransientModel): self.ks_model_show = True else: self.ks_model_show = False - else: - raise ValidationError(_("Please enter URL and API Key in General Settings")) - else: self.ks_model_show = False @@ -88,6 +88,7 @@ class KsDashboardNInjaAI(models.TransientModel): if api_key and url: json_data = {'name': api_key, 'question':question, + 'type': self.ks_type, 'url': self.env['ir.config_parameter'].sudo().get_param('web.base.url'), 'db_name': self.env.cr.dbname } @@ -114,11 +115,11 @@ class KsDashboardNInjaAI(models.TransientModel): if (ks_result == "success"): return { 'type': 'ir.actions.client', - 'name': context['ks_dash_name'], + 'name': 'AI Dashboard', 'params': {'ks_dashboard_id': ks_create_record.id}, - 'tag': 'ks_dashboard_ninja_ai', - 'target': 'new', - 'context': context + 'tag': 'ks_ai_dashboard_ninja', + 'context': context, + 'target':'new' } else: self.env['ks_dashboard_ninja.board'].browse(ks_dash_id).unlink() @@ -212,11 +213,86 @@ class KsDashboardNInjaAI(models.TransientModel): else: raise ValidationError(_("Enter the input keywords to render the item")) + @api.model + def ks_generate_analysis(self,ks_items_explain,ks_rest_items,dashboard_id): + if ks_items_explain: + result = [] + api_key = self.env['ir.config_parameter'].sudo().get_param( + 'ks_dashboard_ninja.dn_api_key') + ks_url = self.env['ir.config_parameter'].sudo().get_param( + 'ks_dashboard_ninja.url') + words = self.env['ir.config_parameter'].sudo().get_param( + 'ks_dashboard_ninja.ks_analysis_word_length') + url = ks_url + "/api/v1/ks_dn_main_api" + for i in range(0,len(ks_items_explain)): + if api_key and url : + json_data = {'name': api_key, + 'items':json.dumps(ks_items_explain[i]), + 'type':'ks_ai_explain', + 'url': self.env['ir.config_parameter'].sudo().get_param('web.base.url'), + 'db_name': self.env.cr.dbname, + 'words': words if words else 100 + } + ks_response = requests.post(url, data=json_data) + if ks_response.status_code == 200 and json.loads(ks_response.text): + ks_ai_response = json.loads(ks_response.text) + item = ks_ai_response[0] + if item['analysis'] and item['insights']: + try: + self.env['ks_dashboard_ninja.item'].browse(item['id']).write({ + 'ks_ai_analysis': item['analysis']+'ks_gap'+item['insights'] + }) + result.append(True) + except: + result + else: + result + else: + result + else: + raise ValidationError(_("Please put API key and URL")) + if len(result): + self.env['ks_dashboard_ninja.board'].browse(dashboard_id).write({ + 'ks_ai_explain_dash': True + }) + return True + else: + raise ValidationError(_("AI Responds with the wrong analysis. Please try again ")) + elif ks_rest_items: + self.env['ks_dashboard_ninja.board'].browse(dashboard_id).write({ + 'ks_ai_explain_dash': True + }) + return True + else: + return False + @api.model + def ks_switch_default_dashboard(self,dashboard_id): + self.env['ks_dashboard_ninja.board'].browse(dashboard_id).write({ + 'ks_ai_explain_dash':False + }) + return True + @api.model + def ks_generatetext_to_speech(self,item_id): + if (item_id): + try: + ks_text = self.env['ks_dashboard_ninja.item'].browse(item_id).ks_ai_analysis + if ks_text: + language = 'en' + ks_myobj = gTTS(text=ks_text, lang=language, slow=False) + ks_file = ks_myobj.save('ks_audio.mp3') + with open('ks_audio.mp3', 'rb') as audio_file: + binary_data = audio_file.read() + wav_file = base64.b64encode( binary_data).decode('UTF-8') + data = {"snd": wav_file} + return json.dumps(data) + else: + return False + except Exception as e: + print(e) + raise ValidationError(_("Some problem in audio generation.")) - - - - + else: + return False diff --git a/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py b/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py index f5ec3a8e0..7096ae328 100644 --- a/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py +++ b/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py @@ -71,10 +71,7 @@ class KsAIDashboardninja(models.TransientModel): if (ks_result == "success"): return { 'type': 'ir.actions.client', - 'name': "Dashboard Ninja", - 'res_model': 'ks_dashboard_ninja.board', - 'params': {'ks_dashboard_id': ks_dash_id}, - 'tag': 'ks_dashboard_ninja', + 'tag': 'reload', } else: self.env['ks_dashboard_ninja.board'].browse(ks_dash_id).unlink() diff --git a/ks_dashboard_ninja/models/ks_child_dashboard.py b/ks_dashboard_ninja/models/ks_child_dashboard.py index acb4eb8da..dfdc9b7a8 100644 --- a/ks_dashboard_ninja/models/ks_child_dashboard.py +++ b/ks_dashboard_ninja/models/ks_child_dashboard.py @@ -15,7 +15,5 @@ class KsDashboardNinjaBoardItemAction(models.Model): company_id = fields.Many2one('res.company', required=True, default=lambda self: self.env.company) - def set_grid_stack_config(self, dashboard_id, gridstack_config): - return self.search([('ks_dashboard_ninja_id', '=', dashboard_id)]).sudo().write({'ks_gridstack_config': gridstack_config}) - - + def write(self,vals): + return super(KsDashboardNinjaBoardItemAction, self).write(vals) diff --git a/ks_dashboard_ninja/models/ks_dashboard_ninja.py b/ks_dashboard_ninja/models/ks_dashboard_ninja.py index c47aec383..65971b0f2 100644 --- a/ks_dashboard_ninja/models/ks_dashboard_ninja.py +++ b/ks_dashboard_ninja/models/ks_dashboard_ninja.py @@ -11,18 +11,6 @@ from odoo.tools.safe_eval import safe_eval import locale from dateutil.parser import parse -def calculate_time(func): - import time - """ - 计算函数执行时间的装饰器 - """ - def wrapper(*args, **kwargs): - start_time = time.time() # 记录开始时间 - result = func(*args, **kwargs) # 执行函数 - end_time = time.time() # 记录结束时间 - print(f"{func.__name__} 函数执行时间: {end_time - start_time} 秒") - return result - return wrapper class KsDashboardNinjaBoard(models.Model): _name = 'ks_dashboard_ninja.board' @@ -113,7 +101,7 @@ class KsDashboardNinjaBoard(models.Model): multi_layouts = fields.Boolean(string='Enable Multi-Dashboard Layouts', help='Allow user to have multiple layouts of the same Dashboard') - + ks_ai_explain_dash = fields.Boolean(default=False); @api.constrains('ks_dashboard_start_date', 'ks_dashboard_end_date') def ks_date_validation(self): for rec in self: @@ -229,7 +217,6 @@ class KsDashboardNinjaBoard(models.Model): return default_grid_id @api.model - @calculate_time def ks_fetch_dashboard_data(self, ks_dashboard_id, ks_item_domain=False): """ Return Dictionary of Dashboard Data. @@ -252,7 +239,7 @@ class KsDashboardNinjaBoard(models.Model): dashboard_data = { 'name': ks_dashboard_rec.name, 'multi_layouts': ks_dashboard_rec.multi_layouts, - 'ks_company_id': self.env.company.id, + 'ks_company_id': self._context.get('allowed_company_ids')[0], 'ks_dashboard_manager': has_group_ks_dashboard_manager, 'ks_dashboard_list': self.search_read([], ['id', 'name']), 'ks_dashboard_start_date': self._context.get('ksDateFilterStartDate', False) or self.browse( @@ -275,6 +262,7 @@ class KsDashboardNinjaBoard(models.Model): ks_dashboard_rec.ks_dashboard_items_ids.read( ['ks_model_name', 'ks_model_name_2'])]), 'ks_model_item_relation': {}, + 'ks_ai_explain_dash':ks_dashboard_rec.ks_ai_explain_dash } default_grid_id = ks_dashboard_rec.ks_get_grid_config() @@ -310,7 +298,6 @@ class KsDashboardNinjaBoard(models.Model): return dashboard_data @api.model - @calculate_time def ks_fetch_item(self, item_list, ks_dashboard_id, params={}): """ :rtype: object @@ -345,6 +332,17 @@ class KsDashboardNinjaBoard(models.Model): action = {} item_domain1 = params.get('ks_domain_1', []) item_domain2 = params.get('ks_domain_2', []) + + ks_action_name = [] + if rec.ks_action_lines: + for res in rec.ks_action_lines: + my_dict = {} + my_dict['id'] = res.id + my_dict['name'] = res.ks_action_item_name + my_dict['sequence'] = res.sequence + ks_action_name.append(my_dict) + ks_action_name.sort(key=lambda r: r['sequence']) + if rec.ks_actions: context = {} try: @@ -408,6 +406,8 @@ class KsDashboardNinjaBoard(models.Model): 'ks_background_color': rec.ks_background_color, 'ks_font_color': rec.ks_font_color, 'ks_header_bg_color': rec.ks_header_bg_color, + # 'ks_domain': rec.ks_domain.replace('"%UID"', str( + # self.env.user.id)) if rec.ks_domain and "%UID" in rec.ks_domain else rec.ks_domain, 'ks_domain': rec.ks_convert_into_proper_domain(rec.ks_domain, rec, item_domain1), 'ks_dashboard_id': rec.ks_dashboard_ninja_board_id.id, 'ks_icon': rec.ks_icon, @@ -463,6 +463,7 @@ class KsDashboardNinjaBoard(models.Model): 'ks_radial_legend': rec.ks_radial_legend, 'ks_data_calculation_type': rec.ks_data_calculation_type, 'ks_export_all_records': rec.ks_export_all_records, + 'ks_data_format': rec.ks_data_format, 'ks_data_formatting': rec.ks_data_format, 'ks_is_client_action': rec.ks_is_client_action, 'ks_pagination_limit': rec.ks_pagination_limit, @@ -484,16 +485,17 @@ class KsDashboardNinjaBoard(models.Model): 'ks_info': rec.ks_info, 'ks_company': rec.ks_company_id.name if rec.ks_company_id else False, 'ks_scatter_measure_x_id': rec.ks_scatter_measure_x_id, - 'ks_scatter_measure_y_id': rec.ks_scatter_measure_y_id, + # 'ks_scatter_measure_y_id': rec.ks_scatter_measure_y_id, 'ks_is_scatter_group': rec.ks_is_scatter_group, - 'ks_radial_item_color': rec.ks_radial_item_color, - 'ks_flower_item_color': rec.ks_flower_item_color, 'ks_bounds': rec.ks_bounds, 'ks_partners_map': rec.ks_partners_map, 'ks_funnel_record_field':rec.ks_funnel_record_field, 'ks_map_record_field':rec.ks_map_record_field, - 'ks_funnel_item_color':rec.ks_funnel_item_color, - 'ks_country_id':rec.ks_country_id.id + 'ks_country_id':rec.ks_country_id.id, + 'ks_action_name':ks_action_name if ks_action_name else False, + 'ks_ai_analysis':rec.ks_ai_analysis + # 'ks_last_index':ks_last_index + # 'ks_id_name':','.join(ks_id_name) } return item @@ -641,6 +643,7 @@ class KsDashboardNinjaBoard(models.Model): 'ks_sort_by_order': res.ks_sort_by_order, 'ks_record_limit': res.ks_record_limit, 'sequence': res.sequence, + 'ks_action_item_name': res.ks_action_item_name } ks_action_lines.append(action_line) ks_multiplier_lines = [] @@ -772,12 +775,11 @@ class KsDashboardNinjaBoard(models.Model): 'ks_data_label_type': rec.ks_data_label_type, 'ks_as_of_now': rec.ks_as_of_now, 'ks_scatter_measure_x_id': rec.ks_chart_relation_groupby.name, - 'ks_scatter_measure_y_id': ks_chart_measure_field, + # 'ks_scatter_measure_y_id': ks_chart_measure_field, 'ks_is_scatter_group': rec.ks_is_scatter_group, 'ks_country_id': rec.ks_country_id.id, 'ks_bounds': rec.ks_bounds, 'ks_partners_map': rec.ks_partners_map, - 'ks_funnel_item_color':rec.ks_funnel_item_color, } if grid_corners: @@ -1189,12 +1191,12 @@ class KsDashboardNinjaBoard(models.Model): else: item['ks_chart_relation_sub_groupby'] = False - if item['ks_dashboard_item_type'] == "ks_scatter_chart" and item['ks_scatter_measure_y_id'] and item[ + if item['ks_dashboard_item_type'] == "ks_scatter_chart" and item[ 'ks_scatter_measure_x_id']: - ks_scatter_id = self.env['ir.model.fields'].search( - [('name', '=', item['ks_scatter_measure_y_id'][0]), ('model', '=', item['ks_model_id'])]) - if ks_scatter_id: - item['ks_scatter_measure_y_id'] = ks_scatter_id.id + # ks_scatter_id = self.env['ir.model.fields'].search( + # [('name', '=', item['ks_scatter_measure_y_id'][0]), ('model', '=', item['ks_model_id'])]) + # if ks_scatter_id: + # item['ks_scatter_measure_y_id'] = ks_scatter_id.id ks_scatter_group_by = item['ks_scatter_measure_x_id'] ks_record_id = self.env['ir.model.fields'].search( [('name', '=', ks_scatter_group_by), ('model', '=', item['ks_model_id'])]) @@ -1204,7 +1206,7 @@ class KsDashboardNinjaBoard(models.Model): item['ks_scatter_measure_x_id'] = False if item["ks_dashboard_item_type"] != "ks_scatter_chart": item['ks_scatter_measure_x_id'] = False - item['ks_scatter_measure_y_id'] = False + # item['ks_scatter_measure_y_id'] = False # Sort by field : Many2one Entery if item['ks_sort_by_field']: @@ -1380,7 +1382,7 @@ class KsDashboardNinjaBoard(models.Model): 'model': rec.ks_model_id.model, 'model_name': rec.ks_model_id.name, 'field_name': rec.ks_domain_field_id.name, - 'field_type': rec.ks_domain_field_id.ttype, + 'type': rec.ks_domain_field_id.ttype, 'special_data': {} } if rec.ks_domain_field_id.ttype == 'selection': diff --git a/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py b/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py index 516dfcc04..40d7966e3 100644 --- a/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py +++ b/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py @@ -28,7 +28,7 @@ _logger = logging.getLogger("DS_NINJA") # TODO : Check all imports if needed -# read = fields.Many2one.read +read = fields.Many2one.read @@ -97,14 +97,16 @@ def ks_read(self, records): comodel._flush_search(domain) wquery = comodel._where_calc(domain) comodel._apply_ir_rules(wquery, 'read') - order_by = comodel._generate_order_by(None, wquery) + sql = comodel._order_to_sql(None, wquery) + order_by_clause = comodel.env.cr.mogrify(sql).decode() + order_by = order_by_clause and (' ORDER BY %s ' % order_by_clause) or '' from_c, where_c, where_params = wquery.get_sql() query = """ SELECT {rel}.{id1}, {rel}.{id2} FROM {rel}, {from_c} WHERE {where_c} AND {rel}.{id1} IN %s AND {rel}.{id2} = {tbl}.id - {order_by} + {order} """.format(rel=self.relation, id1=self.column1, id2=self.column2, tbl=comodel._table, from_c=from_c, where_c=where_c or '1=1', - order_by=order_by) + order=order_by) where_params.append(tuple(records.ids)) # retrieve lines and group them by record @@ -120,9 +122,9 @@ def ks_read(self, records): -# fields.Many2many.read = ks_read FIXME +fields.Many2many.read = ks_read -# read_group = models.BaseModel._read_group_process_groupby FIXME +read_group = models.BaseModel._read_group_groupby def ks_time_addition(self, gb, query): @@ -186,7 +188,7 @@ def ks_time_addition(self, gb, query): } -# models.BaseModel._read_group_process_groupby = ks_time_addition # FIXME +# models.BaseModel._read_group = ks_time_addition class KsDashboardNinjaItems(models.Model): @@ -197,7 +199,7 @@ class KsDashboardNinjaItems(models.Model): ks_info = fields.Text(string="Item Description", translate=True) ks_model_id = fields.Many2one('ir.model', string='Model', domain="[('access_ids','!=',False),('transient','=',False)," - "('model','not ilike','base_import%'),'|',('model','not ilike','ir.%'), ('model','ilike','repair.%')," + "('model','not ilike','base_import%'),'|',('model','not ilike','ir.%'),('model','=ilike','_%ir.%')," "('model','not ilike','web_editor.%'),('model','not ilike','web_tour.%')," "('model','!=','mail.thread'),('model','not ilike','ks_dash%'),('model','not ilike','ks_to%')]", help="Data source to fetch and read the data for the creation of dashboard items. ") @@ -381,7 +383,7 @@ class KsDashboardNinjaItems(models.Model): ('ks_bullet_chart', 'Bullet Chart') ], default=lambda self: self._context.get('ks_dashboard_item_type', 'ks_tile'), required=True, - + string="Dashboard Item Type", help="Select the required type of dashboard to display. ") ks_chart_groupby_type = fields.Char(compute='get_chart_groupby_type', compute_sudo=False) ks_chart_sub_groupby_type = fields.Char(compute='get_chart_sub_groupby_type', compute_sudo=False) @@ -473,7 +475,7 @@ class KsDashboardNinjaItems(models.Model): ks_kpi_data = fields.Char(string="KPI Data", compute="ks_get_kpi_data", compute_sudo=False) ks_chart_item_color = fields.Selection( - [('default', 'Default'), ('cool', 'Cool'), ('warm', 'Warm'), ('neon', 'Neon')], + [('default', 'Default'), ('dark', 'Dark'), ('material', 'Material'), ('moonrise', 'Moonrise')], string="Chart Color Palette", default="default", help='Select the display preference. ') # ------------------------ List View Fields ------------------------------ @@ -563,8 +565,8 @@ class KsDashboardNinjaItems(models.Model): ks_domain_extension = fields.Char('Domain Extension', help="Define conditions for filter to write manually") ks_domain_extension_2 = fields.Char('KPI Domain Extension') # hide legend - ks_hide_legend = fields.Boolean('Show Legend', help="Hide all legend from the chart item", default=True) - ks_radial_legend = fields.Boolean('Show Legend', help="Hide all legend from the chart item", default=True) + ks_hide_legend = fields.Boolean('Show Legend', help="Hide all legend from the chart item", default=False) + ks_radial_legend = fields.Boolean('Show Radial Legend', help="Hide all legend from the chart item", default=False) ks_data_calculation_type = fields.Selection([('custom', 'Default Query'), ('query', 'Custom Query')], string="Data Calculation Type", default="custom", @@ -609,7 +611,7 @@ class KsDashboardNinjaItems(models.Model): # "('ttype','=','integer'),('ttype','=','float')," # "('ttype','=','monetary')]", # string="Measure Y") - ks_is_scatter_group = fields.Boolean(string="Group By") + ks_is_scatter_group = fields.Boolean(string="Scatter Group By") ks_scatter_measure_y_id = fields.Many2one('ir.model.fields', domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," "('store','=',True),'|','|'," @@ -628,9 +630,6 @@ class KsDashboardNinjaItems(models.Model): ks_as_of_now = fields.Boolean("Data Till Now", 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_item_color = fields.Selection( - [('default', 'Default'), ('dark', 'Dark'), ('material', 'Material'), ('moonrise', 'Moonrise')], - string="Radial Chart Theme", default="default", help='Select the display preference. ') ks_map_preview = fields.Char(string="Map Preview", default="Map Preview") ks_partners_map = fields.Char(compute="_compute_map_partners") ks_country_id = fields.Many2one('res.country', string="Country") @@ -648,19 +647,23 @@ class KsDashboardNinjaItems(models.Model): "'|',('ttype','=','integer'),('ttype','=','float')," "('ttype','=','monetary')]", string="Map Record Field") - ks_funnel_item_color = fields.Selection( - [('default', 'Default'), ('dark', 'Dark'), ('material', 'Material'), ('moonrise', 'Moonrise')], - string="Funnel Chart Theme", default="default", help='Select the display preference. ') + + ks_map_chart_relation_groupby = fields.Many2one('ir.model.fields', + domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," + "('store','=',True),('ttype','!=','binary')," + "('ttype','!=','many2many'), ('ttype','!=','one2many'),('relation', '=', 'res.partner')]", + string="Map Group By") + + + ks_bullet_preview = fields.Char(string="Bullet Preview", default="Bullet Preview") ks_flower_view_preview = fields.Char(string="Flower Preview", default="Flower Preview") - ks_flower_item_color = fields.Selection( - [('default', 'Default'), ('dark', 'Dark'), ('material', 'Material'), ('moonrise', 'Moonrise')], - string="Flower Chart Theme", default="default", help='Select the display preference. ') + upload_excel = fields.Binary(string='Upload Excel File', attachment=False) ks_csv_field = fields.Binary(string='Upload CSV File', attachment=False) ks_group_by_lines = fields.One2many('ks.dashboard.group.by', 'ks_dashboard_group_by_id', string="Group By Lines") - ks_csv_group_by_lines = fields.One2many('ks.dashboard.csv.group.by', 'ks_dashboard_csv_group_by_id', string="Group By Lines") + ks_csv_group_by_lines = fields.One2many('ks.dashboard.csv.group.by', 'ks_dashboard_csv_group_by_id', string="CSV Group By Lines") filename = fields.Char(string='Filename') name_seq = fields.Char(help="Sequential Queue ID", copy=False) excel_bool = fields.Boolean(string='Excel Bool') @@ -676,6 +679,10 @@ class KsDashboardNinjaItems(models.Model): [('odoo', 'Odoo'), ('excel', 'Excel'), ('csv', 'CSV')], string="Data Source",default='odoo') + ks_ai_analysis = fields.Char(string='AI Analysis') + + + @api.model def create_ai_dash(self, data, ks_dash_id, model): try: @@ -700,6 +707,7 @@ class KsDashboardNinjaItems(models.Model): ks_measure_field_ids.append(ks_measure_id.id) value["ks_chart_measure_field"] = [(6, 0, ks_measure_field_ids)] + ks_record_id = self.env['ir.model.fields'].search( [('name', '=', item["group_by_column"]), ('model', '=', model)]) if ks_record_id: @@ -791,39 +799,26 @@ class KsDashboardNinjaItems(models.Model): raise ValidationError(_("Getting invalid response from AI, please try again")) - - @api.onchange('ks_chart_relation_groupby', 'ks_model_id','ks_dashboard_item_type') - def add_domain(self): - if self.ks_dashboard_item_type == 'ks_map_view': - return { - 'domain': {'ks_chart_relation_groupby': ['&', '&', '&', '&', '&', '&', ('relation', '=', 'res.partner'), - ('store', '=', True), - ('ttype', '!=', 'many2many'), - ('ttype', '!=', 'one2many'), - ('name', '!=', 'sequence'), - ('name', '!=', 'id'), - ('model_id.name', '=', self.ks_model_id.name) - ]}} - # Making model, csv and excel field invisible on condition. - @api.onchange('data_source') - def ks_make_invisible(self): - if self.data_source == 'excel': - self.excel_bool = True - self.model_bool = False - self.csv_bool = False - elif self.data_source == 'odoo': - self.model_bool = True - self.excel_bool = False - self.csv_bool = False - elif self.data_source == 'csv': - self.csv_bool = True - self.model_bool = False - self.excel_bool = False - elif not self.data_source: - self.model_bool = False - self.excel_bool = False - self.csv_bool = False + @api.onchange('data_source') + def make_invisible(self): + if self.data_source == 'excel': + self.excel_bool = True + self.model_bool = False + self.csv_bool = False + elif self.data_source == 'odoo': + self.model_bool = True + self.excel_bool = False + self.csv_bool = False + elif self.data_source == 'csv': + self.csv_bool = True + self.model_bool = False + self.excel_bool = False + else: + self.model_bool = False + self.excel_bool = False + self.csv_bool = False + # Reading the Csv file @api.onchange('ks_csv_field') @@ -859,8 +854,6 @@ class KsDashboardNinjaItems(models.Model): values = {} for field in fields: values[field] = None - - except: raise ValidationError(_("Invalid file!")) else: @@ -882,37 +875,36 @@ class KsDashboardNinjaItems(models.Model): fp = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") fp.write(binascii.a2b_base64(self.upload_excel)) fp.seek(0) - values = {} - workbook = xlrd.open_workbook(fp.name) - sheet = workbook.sheet_by_index(0) + file_type = os.path.splitext(self.filename) + if file_type[1] == ".xlsx": + df = pd.read_excel(fp.name, engine='openpyxl') + elif file_type[1] == ".xls": + df = pd.read_excel(fp.name, engine='xlrd') + else: + raise ValueError("Unsupported file format. Only XLSX and XLS are supported.") except Exception as e: raise ValidationError(_(e)) - for row_no in range(sheet.nrows): - val = {} - if row_no <= 0: - fields = list( - map(lambda row: isinstance(row.value, bytes) and row.value.encode('utf-8') or str(row.value), - sheet.row(row_no))) - del_group_by_field = """delete from ks_dashboard_new;""" - self._cr.execute(del_group_by_field) - self.env['ks.dashboard.new'].search([]) - for rec in fields: - self.env['ks.dashboard.new'].create({ - 'name': rec, + values = {} + fields = df.columns.tolist() + val = {} + del_group_by_field = """delete from ks_dashboard_new;""" + self._cr.execute(del_group_by_field) + self.env['ks.dashboard.new'].search([]) + for rec in fields: + self.env['ks.dashboard.new'].create({ + 'name': str(rec), + }) + for row_no in range(df.shape[0]): + line = list(df.iloc[row_no]) + value = 0 + for field in fields: + while value < len(line): + values.update({ + field: str(line[value]), }) - else: - line = list( - map(lambda row: isinstance(row.value, bytes) and row.value.encode('utf-8') or str(row.value), - sheet.row(row_no))) - value = 0 - for field in fields: - while (value < len(line)): - values.update({ - field: line[value], - }) - value = value + 1 - break + value += 1 + break else: raise ValidationError('Please add filename which contain Spaces and Underscore in there name only.') else: @@ -925,6 +917,7 @@ class KsDashboardNinjaItems(models.Model): # Syncing the data from table to page def data_sync(self): + print(self.id) data = self.env['ks.dashboard.new'].search([]) for rec in data: self.write({ @@ -968,9 +961,9 @@ class KsDashboardNinjaItems(models.Model): final_split = self.filename.lower().split('_') else: final_split = self.filename.lower().split('.') - tablemodel = ('x_'+final_split[0]+'_'+self.name_seq).replace(' ','') + tablemodel = 'x_'+final_split[0]+'_'+self.name_seq tablename = final_split[0]+' '+self.name_seq - model_creation = self.env['ir.model'].sudo().create({ + model_creation = self.env['ir.model'].create({ 'name': tablename, 'model': tablemodel, 'order': 'x_name asc, id desc', # valid order @@ -1011,21 +1004,21 @@ class KsDashboardNinjaItems(models.Model): fp = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") fp.write(binascii.a2b_base64(self.upload_excel)) fp.seek(0) - values = {} - workbook = xlrd.open_workbook(fp.name) - sheet = workbook.sheet_by_index(0) - except: - raise ValidationError(_("Invalid file!")) - for row_no in range(sheet.nrows): - val = {} - if row_no <= 0: - fields = list( - map(lambda row: isinstance(row.value, bytes) and row.value.encode('utf-8') or str(row.value), - sheet.row(row_no))) + file_type = os.path.splitext(self.filename) + if file_type[1] == ".xlsx": + df = pd.read_excel(fp.name, engine='openpyxl') + elif file_type[1] == ".xls": + df = pd.read_excel(fp.name, engine='xlrd') else: - line = list( - map(lambda row: isinstance(row.value, bytes) and row.value.encode('utf-8') or str(row.value), - sheet.row(row_no))) + raise ValueError("Unsupported file format. Only XLSX and XLS are supported.") + except Exception as e: + raise ValidationError("Invalid file") + df = df.astype(str) + values ={} + fields = df.columns.tolist() + for row_no in range(df.shape[0]): + line = list(df.iloc[row_no]) + val = {} value = 0 for field in fields: if '/' in field: @@ -1036,13 +1029,13 @@ class KsDashboardNinjaItems(models.Model): field = field.replace(')', '').replace('(', '') if field == 'Name': field = field.replace('Name', 'name1') - if 'Date' in field or 'Deadline' in field or self.ks_group_by_lines[value].ttype in ['datetime','date']: - if line[value]: - if self.ks_group_by_lines[value].ttype in['datetime','date']: - final_date = pd.to_timedelta(float(line[value]), unit='D') + pd.to_datetime('1899-12-30') + if 'Date' in field or 'Deadline' in field: + if line[value] != 'NaT' and line[value] !=False: + if self.ks_group_by_lines[value].ttype == 'datetime': + # final_date = pd.to_timedelta(float(line[value]), unit='D') + pd.to_datetime('1899-12-30') while (value < len(line)): values.update({ - field: final_date, + field: line[value], }) value = value + 1 break @@ -1062,7 +1055,7 @@ class KsDashboardNinjaItems(models.Model): break else: while (value < len(line)): - if line[value]: + if line[value] != 'nan' and line[value] !=False: if '.' in line[value]: if ',' in line[value]: if self.ks_group_by_lines[value].ttype == 'char': @@ -1090,7 +1083,7 @@ class KsDashboardNinjaItems(models.Model): }) else: # final_value = (line[value]) - if self.ks_group_by_lines[value].ttype == 'integer': + if self.ks_group_by_lines[value].ttype == 'integer' and line[value]!='nan': try: values.update({ field: int(float(line[value])), @@ -1099,16 +1092,19 @@ class KsDashboardNinjaItems(models.Model): values.update({ field: 0, }) - - elif self.ks_group_by_lines[value].ttype == 'float': + elif self.ks_group_by_lines[value].ttype == 'float'and line[value]!='nan': try: values.update({ field: float(line[value]), }) except: values.update({ - field: 0.00 + field: 0.00, }) + elif line[value] == 'nan': + values.update({ + field: 'Null', + }) else: values.update({ @@ -1128,7 +1124,11 @@ class KsDashboardNinjaItems(models.Model): values.update({ field: final_split_value, }) - elif self.ks_group_by_lines[value].ttype == 'integer': + elif "NaT" in line[value]: + values.update({ + field:'Null', + }) + elif self.ks_group_by_lines[value].ttype == 'integer' and line[value]!='nan': try: values.update({ field: int(float(line[value])), @@ -1137,7 +1137,7 @@ class KsDashboardNinjaItems(models.Model): values.update({ field: 0, }) - elif self.ks_group_by_lines[value].ttype == 'float': + elif self.ks_group_by_lines[value].ttype == 'float' and line[value] != 'nan': try: values.update({ field: float(line[value]), @@ -1193,9 +1193,9 @@ class KsDashboardNinjaItems(models.Model): final_split = self.filename.lower().split('_') else: final_split = self.filename.lower().split('.') - tablemodel = 'x_'+final_split[0]+'_'+self.name_seq.replace(' ','') + tablemodel = 'x_'+final_split[0]+'_'+self.name_seq tablename = final_split[0]+' '+self.name_seq - model_creation = self.env['ir.model'].sudo().create({ + model_creation = self.env['ir.model'].create({ 'name': tablename, 'model': tablemodel, 'order': 'x_name asc, id desc', # valid order @@ -1255,7 +1255,7 @@ class KsDashboardNinjaItems(models.Model): field = field.replace(')', '').replace('(', '') if field == 'Name': field = field.replace('Name', 'name1') - if 'Date' in field or 'Deadline' in field or self.ks_csv_group_by_lines[value].ttype in ['datetime','date']: + if 'Date' in field or 'Deadline' in field: if line[value]: if self.ks_csv_group_by_lines[value].ttype == 'datetime': final_date = line[value].split(' ')[0] @@ -1266,21 +1266,12 @@ class KsDashboardNinjaItems(models.Model): value = value + 1 break else: - try: - while (value < len(line)): - values.update({ - field: line[value], - }) - value = value + 1 - break - except: - while (value < len(line)): - values.update({ - field: 'Null', - }) - value = value + 1 - break - + while (value < len(line)): + values.update({ + field: line[value], + }) + value = value + 1 + break else: while (value < len(line)): values.update({ @@ -1315,25 +1306,13 @@ class KsDashboardNinjaItems(models.Model): split = line[value].split(',') split_value = split[0] + split[1] if self.ks_csv_group_by_lines[value].ttype == 'float': - try: - values.update({ - field: float(split_value), - }) - except: - values.update({ - field: 0.00, - }) - + values.update({ + field: float(split_value), + }) elif self.ks_csv_group_by_lines[value].ttype == 'integer': - try: - values.update({ - field: int(float(split_value)), - }) - except: - values.update({ - field: 0, - }) - + values.update({ + field: int(float(split_value)), + }) else: values.update({ field: split_value, @@ -1344,23 +1323,13 @@ class KsDashboardNinjaItems(models.Model): }) else: if self.ks_csv_group_by_lines[value].ttype == 'float': - try: - values.update({ - field: float(line[value]), - }) - except: - values.update({ - field:0.00, - }) + values.update({ + field: float(line[value]), + }) elif self.ks_csv_group_by_lines[value].ttype == 'integer': - try: - values.update({ - field: int(float(line[value])), - }) - except: - values.update({ - field: 0, - }) + values.update({ + field: int(float(line[value])), + }) else: values.update({ field: line[value], @@ -1385,24 +1354,14 @@ class KsDashboardNinjaItems(models.Model): }) value = value + 1 break - elif self.ks_csv_group_by_lines[value].ttype == 'integer': - try: - values.update({ - field: int(float(line[value])), - }) - except: - values.update({ - field: 0, - }) elif self.ks_csv_group_by_lines[value].ttype == 'float': - try: - values.update({ - field: float(line[value]), - }) - except: - values.update({ - field: 0.00, - }) + values.update({ + field: float(line[value]), + }) + elif self.ks_csv_group_by_lines[value].ttype == 'integer': + values.update({ + field: int(float(line[value])), + }) else: values.update({ field: line[value], @@ -1536,10 +1495,6 @@ class KsDashboardNinjaItems(models.Model): if len(rec.ks_chart_measure_field) == 0: rec.ks_chart_cumulative_field = False - - - - @api.onchange('ks_list_view_type') def _ks_onchange_ks_list_view_type(self): for rec in self: @@ -1594,8 +1549,6 @@ class KsDashboardNinjaItems(models.Model): if not rec.ks_record_data_limit_visibility: rec.ks_record_data_limit = 0 - - @api.onchange('ks_fill_temporal') def ks_onchange_fill_temporal(self): if self.ks_fill_temporal: @@ -1846,6 +1799,7 @@ class KsDashboardNinjaItems(models.Model): rec.ks_date_filter_field = False # Pro rec.ks_funnel_record_field = False + rec.ks_map_chart_relation_groupby = False rec.ks_map_record_field = False rec.ks_record_field = False rec.ks_chart_measure_field = False @@ -2098,6 +2052,7 @@ class KsDashboardNinjaItems(models.Model): ks_extensiom_domain = ks_extensiom_domain.replace('"%UID"', str(self.env.user.id)) if "%UID" in ks_extensiom_domain: ks_extensiom_domain = ks_extensiom_domain.replace("'%UID'", str(self.env.user.id)) + print(ks_extensiom_domain) if ks_extensiom_domain and "%MYCOMPANY" in ks_extensiom_domain: ks_extensiom_domain = ks_extensiom_domain.replace('"%MYCOMPANY"', str(self.env.company.id)) @@ -2232,650 +2187,647 @@ class KsDashboardNinjaItems(models.Model): 'ks_chart_date_sub_groupby', 'ks_date_filter_field', 'ks_item_start_date', 'ks_item_end_date', 'ks_compare_period', 'ks_year_period', 'ks_unit', 'ks_unit_selection', 'ks_chart_unit', 'ks_fill_temporal', 'ks_domain_extension', 'ks_multiplier_active', 'ks_multiplier_lines', - 'ks_scatter_measure_x_id', 'ks_scatter_measure_y_id') + 'ks_scatter_measure_x_id','ks_map_chart_relation_groupby') def ks_get_chart_data(self): for rec in self: if rec.ks_dashboard_item_type == "ks_funnel_chart": rec.ks_sort_by_order = "DESC" rec.ks_sort_by_field = rec.ks_funnel_record_field + rec.ks_chart_relation_sub_groupby = False rec.ks_chart_measure_field = rec.ks_funnel_record_field rec.ks_chart_data = rec._ks_get_chart_data(domain=[]) elif rec.ks_dashboard_item_type == "ks_map_view": rec.ks_chart_measure_field = rec.ks_map_record_field + rec.ks_chart_relation_groupby = rec.ks_map_chart_relation_groupby rec.ks_chart_data = rec._ks_get_chart_data(domain=[]) elif rec.ks_dashboard_item_type == "ks_scatter_chart": - rec.ks_chart_measure_field = rec.ks_scatter_measure_x_id - rec.ks_chart_relation_groupby = rec.ks_scatter_measure_y_id + rec.ks_chart_relation_groupby = rec.ks_scatter_measure_x_id + # rec.ks_chart_relation_groupby = rec.ks_scatter_measure_y_id rec.ks_chart_data = rec._ks_get_chart_data(domain=[]) else: rec.ks_chart_data = rec._ks_get_chart_data(domain=[]) - def _ks_get_chart_data(self, domain=[]): - if not all([self.ks_dashboard_item_type, self.ks_dashboard_item_type not in ['ks_tile', 'ks_list_view'], - self.ks_model_id, self.ks_chart_data_count_type]): - return False + rec = self + if rec.ks_dashboard_item_type and rec.ks_dashboard_item_type != 'ks_tile' and \ + rec.ks_dashboard_item_type != 'ks_list_view' and rec.ks_model_id and rec.ks_chart_data_count_type: + ks_chart_data = {'labels': [], 'datasets': [], 'ks_currency': 0, 'ks_field': "", 'ks_selection': "", + 'ks_show_second_y_scale': False, 'domains': [], } + ks_chart_measure_field = [] + ks_chart_measure_field_with_type = [] + ks_chart_measure_field_ids = [] + ks_chart_measure_field_2 = [] + ks_chart_measure_field_with_type_2 = [] + ks_chart_measure_field_2_ids = [] - ks_chart_data = { - 'labels': [], - 'datasets': [], - 'ks_currency': 0, - 'ks_field': "", - 'ks_selection': "", - 'ks_show_second_y_scale': False, - 'domains': [], - } - ks_chart_measure_field = [] - ks_chart_measure_field_with_type = [] - ks_chart_measure_field_ids = [] - ks_chart_measure_field_2 = [] - ks_chart_measure_field_with_type_2 = [] - ks_chart_measure_field_2_ids = [] + if rec.ks_unit and rec.ks_unit_selection == 'monetary': + ks_chart_data['ks_selection'] += rec.ks_unit_selection + ks_chart_data['ks_currency'] += rec.env.user.company_id.currency_id.id + elif rec.ks_unit and rec.ks_unit_selection == 'custom': + ks_chart_data['ks_selection'] += rec.ks_unit_selection + if rec.ks_chart_unit: + ks_chart_data['ks_field'] += rec.ks_chart_unit - if self.ks_unit and self.ks_unit_selection == 'monetary': - ks_chart_data['ks_selection'] += self.ks_unit_selection - ks_chart_data['ks_currency'] += self.env.user.company_id.currency_id.id - elif self.ks_unit and self.ks_unit_selection == 'custom': - ks_chart_data['ks_selection'] += self.ks_unit_selection - if self.ks_chart_unit: - ks_chart_data['ks_field'] += self.ks_chart_unit + # If count chart data type: + if rec.ks_chart_data_count_type == "count": + rec.ks_chart_measure_field = False + rec.ks_chart_measure_field_2 = False + if not rec.ks_sort_by_field: + ks_chart_measure_field_with_type.append('count:count(id)') + elif rec.ks_sort_by_field: + if rec.ks_sort_by_field.ttype == "many2one" and rec.ks_sort_by_field.name == rec.ks_chart_relation_groupby.name: + ks_chart_measure_field_with_type.append(rec.ks_sort_by_field.name) + elif not rec.ks_sort_by_field.ttype in ["datetime",'date']: + ks_chart_measure_field_with_type.append(rec.ks_sort_by_field.name + ':' + 'sum') + else: + ks_chart_measure_field_with_type.append(rec.ks_sort_by_field.name) - if self.ks_chart_data_count_type == "count": - self.ks_chart_measure_field = False - self.ks_chart_measure_field_2 = False - if not self.ks_sort_by_field: - ks_chart_measure_field_with_type.append('count:count(id)') - elif self.ks_sort_by_field: - if not self.ks_sort_by_field.ttype == "datetime": - ks_chart_measure_field_with_type.append(self.ks_sort_by_field.name + ':' + 'sum') - else: - ks_chart_measure_field_with_type.append(self.ks_sort_by_field.name) + ks_chart_data['datasets'].append({'data': [], 'label': "Count"}) + else: + if rec.ks_dashboard_item_type == 'ks_bar_chart': + if rec.ks_chart_measure_field_2: + ks_chart_data['ks_show_second_y_scale'] = True + for res in rec.ks_chart_measure_field_2: + if rec.ks_chart_data_count_type == 'sum': + ks_data_count_type = 'sum' + elif rec.ks_chart_data_count_type == 'average': + ks_data_count_type = 'avg' + else: + raise ValidationError(_('Please chose any Data Type!')) + ks_chart_measure_field_2.append(res.name) + ks_chart_measure_field_with_type_2.append(res.name + ':' + ks_data_count_type) + ks_chart_measure_field_2_ids.append(res.id) + ks_chart_data['datasets'].append( + {'data': [], 'label': res.field_description, 'type': 'line', 'yAxisID': 'y-axis-1'}) - ks_chart_data['datasets'].append({'data': [], 'label': "Count"}) - else: - if self.ks_dashboard_item_type == 'ks_bar_chart' and self.ks_chart_measure_field_2: - ks_chart_data['ks_show_second_y_scale'] = True - for res in self.ks_chart_measure_field_2: - if self.ks_chart_data_count_type == 'sum': + for res in range(0, len(rec.ks_chart_measure_field)): + if rec.ks_chart_data_count_type == 'sum': ks_data_count_type = 'sum' - elif self.ks_chart_data_count_type == 'average': + elif rec.ks_chart_data_count_type == 'average': ks_data_count_type = 'avg' else: raise ValidationError(_('Please chose any Data Type!')) - ks_chart_measure_field_2.append(res.name) - ks_chart_measure_field_with_type_2.append(res.name + ':' + ks_data_count_type) - ks_chart_measure_field_2_ids.append(res.id) - ks_chart_data['datasets'].append({'data': [], 'label': res.field_description, 'type': 'line', 'yAxisID': 'y-axis-1'}) + ks_chart_measure_field_with_type.append( + rec.ks_chart_measure_field[res].name + ':' + ks_data_count_type) + ks_chart_measure_field.append(rec.ks_chart_measure_field[res].name) + ks_chart_measure_field_ids.append(rec.ks_chart_measure_field[res].ids[0]) - for res in range(0, len(self.ks_chart_measure_field)): - if self.ks_chart_data_count_type == 'sum': - ks_data_count_type = 'sum' - elif self.ks_chart_data_count_type == 'average': - ks_data_count_type = 'avg' - else: - raise ValidationError(_('Please chose any Data Type!')) - ks_chart_measure_field_with_type.append( - self.ks_chart_measure_field[res].name + ':' + ks_data_count_type) - ks_chart_measure_field.append(self.ks_chart_measure_field[res].name) - ks_chart_measure_field_ids.append(self.ks_chart_measure_field[res].ids[0]) + if len(rec.ks_chart_cumulative_field) > len(rec.ks_chart_measure_field): + rec.ks_chart_cumulative_field = rec.ks_chart_measure_field - if len(self.ks_chart_cumulative_field) > len(self.ks_chart_measure_field): - self.ks_chart_cumulative_field = self.ks_chart_measure_field + if rec.ks_chart_cumulative_field and res < len(rec.ks_chart_cumulative_field) and \ + (rec.ks_chart_cumulative_field[res].id or rec.ks_chart_cumulative_field[res].id.origin) in rec.ks_chart_measure_field.ids: - if (self.ks_chart_cumulative_field and res < len(self.ks_chart_cumulative_field) - and (self.ks_chart_cumulative_field[res].id or self.ks_chart_cumulative_field[res].id.origin) in self.ks_chart_measure_field.ids): + ks_chart_data['datasets'].append( + {'data': [], 'label': rec.ks_chart_cumulative_field[res].field_description, + 'ks_chart_cumulative_field': True, 'ks_as_of_now': rec.ks_as_of_now}) + else: + ks_chart_data['datasets'].append( + {'data': [], 'label': rec.ks_chart_measure_field[res].field_description, + 'ks_chart_cumulative_field': False, 'ks_as_of_now': rec.ks_as_of_now}) - ks_chart_data['datasets'].append( - {'data': [], 'label': self.ks_chart_cumulative_field[res].field_description, - 'ks_chart_cumulative_field': True, 'ks_as_of_now': self.ks_as_of_now}) - else: - ks_chart_data['datasets'].append( - {'data': [], 'label': self.ks_chart_measure_field[res].field_description, - 'ks_chart_cumulative_field': False, 'ks_as_of_now': self.ks_as_of_now}) - - ks_chart_groupby_relation_field = self.ks_chart_relation_groupby.name - ks_chart_domain = self.ks_convert_into_proper_domain(self.ks_domain, self, domain) - ks_chart_data['previous_domain'] = ks_chart_domain - if self.ks_chart_data_count_type == "count" and not self.ks_fill_temporal and not self.ks_sort_by_field: - orderby = 'count' - else: - orderby = self.ks_sort_by_field.name if self.ks_sort_by_field else False - if self.ks_sort_by_order: - orderby = orderby + " " + self.ks_sort_by_order - limit = self.ks_record_data_limit if self.ks_record_data_limit and self.ks_record_data_limit > 0 else 5000 - if self.ks_as_of_now: - limit = 5000 - - if (((self.ks_chart_data_count_type != "count" and ks_chart_measure_field) - or (self.ks_chart_data_count_type == "count" and not ks_chart_measure_field)) - and not self.ks_chart_relation_sub_groupby): - if self.ks_chart_relation_groupby.ttype == 'date' and self.ks_chart_date_groupby in ('minute', 'hour'): - raise ValidationError(_('Groupby field: {} cannot be aggregated by {}').format(self.ks_chart_relation_groupby.display_name, self.ks_chart_date_groupby)) - elif self.ks_chart_date_groupby == 'month_year': - ks_chart_date_groupby = 'month' + # ks_chart_measure_field = [res.name for res in rec.ks_chart_measure_field] + ks_chart_groupby_relation_field = rec.ks_chart_relation_groupby.name + ks_chart_domain = self.ks_convert_into_proper_domain(rec.ks_domain, rec, domain) + ks_chart_data['previous_domain'] = ks_chart_domain + if rec.ks_chart_data_count_type == "count" and not self.ks_fill_temporal and not rec.ks_sort_by_field: + orderby = 'count' else: - ks_chart_date_groupby = self.ks_chart_date_groupby + orderby = rec.ks_sort_by_field.name if rec.ks_sort_by_field else False + if rec.ks_sort_by_order and orderby : + orderby = orderby + " " + rec.ks_sort_by_order + limit = rec.ks_record_data_limit if rec.ks_record_data_limit and rec.ks_record_data_limit > 0 else 5000 + if rec.ks_as_of_now: + limit=5000 - if (self.ks_chart_groupby_type == 'date_type' and self.ks_chart_date_groupby) or self.ks_chart_groupby_type != 'date_type': - ks_chart_data = self.ks_fetch_chart_data(self.ks_model_name, - ks_chart_domain, - ks_chart_measure_field_with_type, - ks_chart_measure_field_with_type_2, - ks_chart_measure_field, - ks_chart_measure_field_2, - ks_chart_groupby_relation_field, - ks_chart_date_groupby, - self.ks_chart_groupby_type, - orderby, - limit, - self.ks_chart_data_count_type, - ks_chart_measure_field_ids, - ks_chart_measure_field_2_ids, - self.ks_chart_relation_groupby.id, - ks_chart_data) - - if (self.ks_chart_groupby_type == 'date_type' - and self.ks_goal_enable - and self.ks_dashboard_item_type in ['ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart','ks_area_chart'] - and self.ks_chart_groupby_type == "date_type"): - - if self._context.get('current_id', False): - ks_item_id = self._context['current_id'] - else: - ks_item_id = self.id - - if self.ks_date_filter_selection == "l_none": - selected_start_date = self._context.get('ksDateFilterStartDate', False) - selected_end_date = self._context.get('ksDateFilterEndDate', False) - - else: - if self.ks_date_filter_selection == "l_custom": - selected_start_date = self.ks_item_start_date - selected_end_date = self.ks_item_end_date - else: - ks_date_data = ks_get_date(self.ks_date_filter_selection, self, self.ks_date_filter_field.ttype) - selected_start_date = ks_date_data["selected_start_date"] - selected_end_date = ks_date_data["selected_end_date"] - - if selected_start_date and selected_end_date: - selected_start_date = selected_start_date.strftime('%Y-%m-%d') - selected_end_date = selected_end_date.strftime('%Y-%m-%d') - ks_goal_domain = [('ks_dashboard_item', '=', ks_item_id)] - - if selected_start_date and selected_end_date: - ks_goal_domain.extend([('ks_goal_date', '>=', selected_start_date.split(" ")[0]), - ('ks_goal_date', '<=', selected_end_date.split(" ")[0])]) - - ks_date_data = self.ks_get_start_end_date(self.ks_model_name, - ks_chart_groupby_relation_field, - self.ks_chart_relation_groupby.ttype, - ks_chart_domain, - ks_goal_domain) - - labels = [] - if self.ks_chart_date_groupby == 'month_year': - ks_chart_date_groupby = 'month' - else: - ks_chart_date_groupby = self.ks_chart_date_groupby - if ks_date_data['start_date'] and ks_date_data['end_date'] and self.ks_goal_lines: - labels = self.generate_timeserise(ks_date_data['start_date'], ks_date_data['end_date'], ks_chart_date_groupby) - - ks_goal_records = self.env['ks_dashboard_ninja.item_goal'].read_group(ks_goal_domain, ['ks_goal_value'], ['ks_goal_date' + ":" + ks_chart_date_groupby], lazy=False) - - ks_goal_labels = [] - ks_goal_dataset = [] - goal_dataset = [] - - if self.ks_goal_lines and len(self.ks_goal_lines) != 0: - ks_goal_domains = {} - for res in ks_goal_records: - if res['ks_goal_date' + ":" + ks_chart_date_groupby]: - ks_goal_labels.append(res['ks_goal_date' + ":" + ks_chart_date_groupby]) - ks_goal_dataset.append(res['ks_goal_value']) - ks_goal_domains[res['ks_goal_date' + ":" + ks_chart_date_groupby]] = res['__domain'] - - for goal_domain in ks_goal_domains.keys(): - ks_goal_doamins = [] - for item in ks_goal_domains[goal_domain]: - - if 'ks_goal_date' in item: - domain = list(item) - domain[0] = ks_chart_groupby_relation_field - domain = tuple(domain) - ks_goal_doamins.append(domain) - ks_goal_doamins.insert(0, '&') - ks_goal_domains[goal_domain] = ks_goal_doamins - - domains = {} - counter = 0 - for label in ks_chart_data['labels']: - domains[label] = ks_chart_data['domains'][counter] - counter += 1 - - ks_chart_records_dates = ks_chart_data['labels'] + list( - set(ks_goal_labels) - set(ks_chart_data['labels'])) - - ks_chart_records = [] - for label in labels: - if label in ks_chart_records_dates: - ks_chart_records.append(label) - - ks_chart_data['domains'].clear() - datasets = [] - for dataset in ks_chart_data['datasets']: - datasets.append(dataset['data'].copy()) - - for dataset in ks_chart_data['datasets']: - dataset['data'].clear() - - for label in ks_chart_records: - domain = domains.get(label, False) - if domain: - ks_chart_data['domains'].append(domain) - else: - ks_chart_data['domains'].append(ks_goal_domains.get(label, [])) - counterr = 0 - if label in ks_chart_data['labels']: - index = ks_chart_data['labels'].index(label) - - for dataset in ks_chart_data['datasets']: - dataset['data'].append(datasets[counterr][index]) - counterr += 1 - - else: - for dataset in ks_chart_data['datasets']: - dataset['data'].append(0.00) - - if label in ks_goal_labels: - index = ks_goal_labels.index(label) - goal_dataset.append(ks_goal_dataset[index]) - else: - goal_dataset.append(0.00) - - ks_chart_data['labels'] = ks_chart_records - else: - if self.ks_standard_goal_value: - length = len(ks_chart_data['datasets'][0]['data']) - for _ in range(length): - goal_dataset.append(self.ks_standard_goal_value) - ks_goal_datasets = { - 'label': 'Target', - 'data': goal_dataset, - 'ks_as_of_now': False - } - if self.ks_goal_bar_line: - ks_goal_datasets['type'] = 'line' - ks_chart_data['datasets'].insert(0, ks_goal_datasets) - else: - ks_chart_data['datasets'].append(ks_goal_datasets) - - elif self.ks_chart_relation_sub_groupby and ((self.ks_chart_sub_groupby_type == 'relational_type') or - (self.ks_chart_sub_groupby_type == 'selection') or - (self.ks_chart_sub_groupby_type == 'date_type' and - self.ks_chart_date_sub_groupby) or - (self.ks_chart_sub_groupby_type == 'other')): - if self.ks_chart_relation_sub_groupby.ttype == 'date': - if self.ks_chart_date_sub_groupby in ('minute', 'hour'): - raise ValidationError(_('Sub Groupby field: {} cannot be aggregated by {}').format( - self.ks_chart_relation_sub_groupby.display_name, self.ks_chart_date_sub_groupby)) - if self.ks_chart_date_groupby in ('minute', 'hour'): + if ((rec.ks_chart_data_count_type != "count" and ks_chart_measure_field) or ( + rec.ks_chart_data_count_type == "count" and not ks_chart_measure_field)) \ + and not rec.ks_chart_relation_sub_groupby: + if rec.ks_chart_relation_groupby.ttype == 'date' and rec.ks_chart_date_groupby in ( + 'minute', 'hour'): raise ValidationError(_('Groupby field: {} cannot be aggregated by {}').format( - self.ks_chart_relation_sub_groupby.display_name, self.ks_chart_date_groupby)) - - ks_chart_date_sub_groupby = self.ks_chart_date_sub_groupby - ks_chart_date_groupby = self.ks_chart_date_groupby - else: - ks_chart_date_sub_groupby = self.ks_chart_date_sub_groupby - if self.ks_chart_date_groupby == 'month_year': + rec.ks_chart_relation_groupby.display_name, rec.ks_chart_date_groupby)) + ks_chart_date_groupby = 'day' + elif rec.ks_chart_date_groupby == 'month_year': ks_chart_date_groupby = 'month' else: - ks_chart_date_groupby = self.ks_chart_date_groupby - if len(ks_chart_measure_field) != 0 or self.ks_chart_data_count_type == 'count': - if self.ks_chart_groupby_type == 'date_type' and ks_chart_date_groupby: - ks_chart_group = self.ks_chart_relation_groupby.name + ":" + ks_chart_date_groupby - else: - ks_chart_group = self.ks_chart_relation_groupby.name + ks_chart_date_groupby = rec.ks_chart_date_groupby - if self.ks_chart_sub_groupby_type == 'date_type' and self.ks_chart_date_sub_groupby: - ks_chart_sub_groupby_field = self.ks_chart_relation_sub_groupby.name + ":" + ks_chart_date_sub_groupby - else: - ks_chart_sub_groupby_field = self.ks_chart_relation_sub_groupby.name + if (rec.ks_chart_groupby_type == 'date_type' and rec.ks_chart_date_groupby) or \ + rec.ks_chart_groupby_type != 'date_type': + ks_chart_data = rec.ks_fetch_chart_data(rec.ks_model_name, ks_chart_domain, + ks_chart_measure_field_with_type, + ks_chart_measure_field_with_type_2, + ks_chart_measure_field, + ks_chart_measure_field_2, + ks_chart_groupby_relation_field, + ks_chart_date_groupby, + rec.ks_chart_groupby_type, orderby, limit, + rec.ks_chart_data_count_type, + ks_chart_measure_field_ids, + ks_chart_measure_field_2_ids, + rec.ks_chart_relation_groupby.id, ks_chart_data) - ks_chart_groupby_relation_fields = [ks_chart_group, ks_chart_sub_groupby_field] - ks_chart_record = False - try: - ks_chart_record = self.env[self.ks_model_name].read_group(ks_chart_domain, - list(set( - ks_chart_measure_field_with_type + - ks_chart_measure_field_with_type_2 + - [ - ks_chart_groupby_relation_field, - self.ks_chart_relation_sub_groupby.name])), - ks_chart_groupby_relation_fields, - orderby=orderby, limit=limit, - lazy=False) - except Exception: - ks_chart_record = {} - chart_data = [] - chart_sub_data = [] - for res in ks_chart_record: - domain = res.get('__domain', []) - if res.get(ks_chart_groupby_relation_fields[0], False): - if self.ks_chart_groupby_type == 'date_type': - # x-axis modification - if self.ks_chart_date_groupby == "day" and self.ks_chart_date_sub_groupby in ["quarter", "year"]: - label = " ".join(res[ks_chart_groupby_relation_fields[0]].split(" ")[0:2]) - elif self.ks_chart_date_groupby in ["minute", "hour"] and \ - self.ks_chart_date_sub_groupby in ["month", "week", "quarter", "year"]: - label = " ".join(res[ks_chart_groupby_relation_fields[0]].split(" ")[0:3]) - elif self.ks_chart_date_groupby == 'month_year': - label = res[ks_chart_groupby_relation_fields[0]] + if rec.ks_chart_groupby_type == 'date_type' and rec.ks_goal_enable and rec.ks_dashboard_item_type in [ + 'ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', + 'ks_area_chart'] and rec.ks_chart_groupby_type == "date_type": + + if rec._context.get('current_id', False): + ks_item_id = rec._context['current_id'] + else: + ks_item_id = rec.id + + if rec.ks_date_filter_selection == "l_none": + selected_start_date = rec._context.get('ksDateFilterStartDate', False) + selected_end_date = rec._context.get('ksDateFilterEndDate', False) + + else: + if rec.ks_date_filter_selection == "l_custom": + selected_start_date = rec.ks_item_start_date + selected_end_date = rec.ks_item_end_date else: - label = res[ks_chart_groupby_relation_fields[0]].split(" ")[0] - elif self.ks_chart_groupby_type == 'selection': - selection = res[ks_chart_groupby_relation_fields[0]] - label = dict(self.env[self.ks_model_name].fields_get( - allfields=[ks_chart_groupby_relation_fields[0]]) - [ks_chart_groupby_relation_fields[0]]['selection'])[selection] - elif self.ks_chart_groupby_type == 'relational_type': - label = res[ks_chart_groupby_relation_fields[0]][1] - elif self.ks_chart_groupby_type == 'other': - label = res[ks_chart_groupby_relation_fields[0]] + ks_date_data = ks_get_date(rec.ks_date_filter_selection, self, + rec.ks_date_filter_field.ttype) + selected_start_date = ks_date_data["selected_start_date"] + selected_end_date = ks_date_data["selected_end_date"] + + if selected_start_date and selected_end_date: + selected_start_date = selected_start_date.strftime('%Y-%m-%d') + selected_end_date = selected_end_date.strftime('%Y-%m-%d') + ks_goal_domain = [('ks_dashboard_item', '=', ks_item_id)] + + if selected_start_date and selected_end_date: + ks_goal_domain.extend([('ks_goal_date', '>=', selected_start_date.split(" ")[0]), + ('ks_goal_date', '<=', selected_end_date.split(" ")[0])]) + + ks_date_data = rec.ks_get_start_end_date(rec.ks_model_name, ks_chart_groupby_relation_field, + rec.ks_chart_relation_groupby.ttype, + ks_chart_domain, + ks_goal_domain) labels = [] - value = [] - value_2 = [] - labels_2 = [] - if self.ks_chart_data_count_type != 'count': - for ress in self.ks_chart_measure_field: - if self.ks_chart_sub_groupby_type == 'date_type': - if res[ks_chart_groupby_relation_fields[1]] is not False: - labels.append(res[ks_chart_groupby_relation_fields[1]].split(" ")[ - 0] + " " + ress.field_description) - else: - labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + " " + - ress.field_description) - elif self.ks_chart_sub_groupby_type == 'selection': - if res[ks_chart_groupby_relation_fields[1]] is not False: - selection = res[ks_chart_groupby_relation_fields[1]] - labels.append(dict(self.env[self.ks_model_name].fields_get( - allfields=[ks_chart_groupby_relation_fields[1]]) - [ks_chart_groupby_relation_fields[1]]['selection'])[ - selection] - + " " + ress.field_description) - else: - labels.append(str(res[ks_chart_groupby_relation_fields[1]])) - elif self.ks_chart_sub_groupby_type == 'relational_type': - if res[ks_chart_groupby_relation_fields[1]] is not False: - labels.append(res[ks_chart_groupby_relation_fields[1]][1] - + " " + ress.field_description) - else: - labels.append(str(res[ks_chart_groupby_relation_fields[1]]) - + " " + ress.field_description) - elif self.ks_chart_sub_groupby_type == 'other': - if res[ks_chart_groupby_relation_fields[1]] is not False: - labels.append(str(res[ks_chart_groupby_relation_fields[1]]) - + "\'s " + ress.field_description) - else: - labels.append(str(res[ks_chart_groupby_relation_fields[1]]) - + " " + ress.field_description) - - value.append(res.get(ress.name, 0)) - - if self.ks_chart_measure_field_2 and self.ks_dashboard_item_type == 'ks_bar_chart': - for ress in self.ks_chart_measure_field_2: - if self.ks_chart_sub_groupby_type == 'date_type': - if res[ks_chart_groupby_relation_fields[1]] is not False: - labels_2.append( - res[ks_chart_groupby_relation_fields[1]].split(" ")[0] + " " - + ress.field_description) - else: - labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + - " " + ress.field_description) - elif self.ks_chart_sub_groupby_type == 'selection': - selection = res[ks_chart_groupby_relation_fields[1]] - labels_2.append(dict(self.env[self.ks_model_name].fields_get( - allfields=[ks_chart_groupby_relation_fields[1]]) - [ks_chart_groupby_relation_fields[1]][ - 'selection'])[ - selection] + " " + ress.field_description) - elif self.ks_chart_sub_groupby_type == 'relational_type': - if res[ks_chart_groupby_relation_fields[1]] is not False: - labels_2.append( - res[ks_chart_groupby_relation_fields[1]][1] + " " + - ress.field_description) - else: - labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + - " " + ress.field_description) - elif self.ks_chart_sub_groupby_type == 'other': - labels_2.append(str( - res[ks_chart_groupby_relation_fields[1]]) + " " + - ress.field_description) - - value_2.append(res.get( - ress.name, 0)) - - chart_sub_data.append({ - 'value': value_2, - 'labels': label, - 'series': labels_2, - 'domain': domain, - }) + if rec.ks_chart_date_groupby == 'month_year': + ks_chart_date_groupby = 'month' else: - if self.ks_chart_sub_groupby_type == 'date_type': - if res[ks_chart_groupby_relation_fields[1]] is not False: - labels.append(res[ks_chart_groupby_relation_fields[1]].split(" ")[0]) - else: - labels.append(str(res[ks_chart_groupby_relation_fields[1]])) - elif self.ks_chart_sub_groupby_type == 'selection': - selection = res[ks_chart_groupby_relation_fields[1]] - if selection: - labels.append(dict(self.env[self.ks_model_name].fields_get( - allfields=[ks_chart_groupby_relation_fields[1]]) - [ks_chart_groupby_relation_fields[1]]['selection'])[ - selection]) - elif self.ks_chart_sub_groupby_type == 'relational_type': - if res[ks_chart_groupby_relation_fields[1]] is not False: - labels.append(res[ks_chart_groupby_relation_fields[1]][1]) - else: - labels.append(str(res[ks_chart_groupby_relation_fields[1]])) - elif self.ks_chart_sub_groupby_type == 'other': - labels.append(res[ks_chart_groupby_relation_fields[1]]) - value.append(res['__count']) + ks_chart_date_groupby = rec.ks_chart_date_groupby + if ks_date_data['start_date'] and ks_date_data['end_date'] and rec.ks_goal_lines: + labels = self.generate_timeserise(ks_date_data['start_date'], ks_date_data['end_date'], + ks_chart_date_groupby) - chart_data.append({ - 'value': value, - 'labels': label, - 'series': labels, - 'domain': domain, - }) - - xlabels = [] - series = [] - values = {'ks_sub_domain': {}} - domains = {} - for data in chart_data: - label = data['labels'] - serie = data['series'] - domain = data['domain'] - ks_sub_group_domain = data['domain'].copy() - - if (len(xlabels) == 0) or (label not in xlabels): - xlabels.append(label) - - if (label not in domains): - domains[label] = domain - else: - domains[label].insert(0, '|') - domains[label] = domains[label] + domain - - series = series + serie - value = data['value'] - counter = 0 - for seri in serie: - if seri not in values: - values[seri] = {'ks_sub_domain': {}} - if label in values[seri]: - values[seri][label] = values[seri][label] + value[counter] - values[seri]['ks_sub_domain'][label] = ks_sub_group_domain - - else: - values[seri][label] = value[counter] - values[seri]['ks_sub_domain'][label] = ks_sub_group_domain - counter += 1 - - final_datasets = [] - for serie in series: - if serie not in final_datasets: - final_datasets.append(serie) - - ks_data = [] - for dataset in final_datasets: - ks_dataset = { - 'value': [], - 'key': dataset - } - for label in xlabels: - ks_dataset['value'].append({ - 'domain': domains[label], - 'x': label, - 'y': values[dataset][label] if label in values[dataset] else 0, - 'ks_sub_domain': values[dataset]['ks_sub_domain'][label] if values[dataset].get( - 'ks_sub_domain', False) and values[dataset]['ks_sub_domain'].get(label, False) else [] - - }) - ks_data.append(ks_dataset) - - if self.ks_chart_relation_sub_groupby.name == self.ks_chart_relation_groupby.name == self.ks_sort_by_field.name: - ks_data = self.ks_sort_sub_group_by_records(ks_data, self.ks_chart_groupby_type, - self.ks_chart_date_groupby, self.ks_sort_by_order, - self.ks_chart_date_sub_groupby) - - ks_chart_data = { - 'labels': [], - 'datasets': [], - 'domains': [], - 'ks_selection': "", - 'ks_currency': 0, - 'ks_field': "", - 'previous_domain': ks_chart_domain - } - - if self.ks_unit and self.ks_unit_selection == 'monetary': - ks_chart_data['ks_selection'] += self.ks_unit_selection - ks_chart_data['ks_currency'] += self.env.user.company_id.currency_id.id - elif self.ks_unit and self.ks_unit_selection == 'custom': - ks_chart_data['ks_selection'] += self.ks_unit_selection - if self.ks_chart_unit: - ks_chart_data['ks_field'] += self.ks_chart_unit - - if len(ks_data) != 0: - for res in ks_data[0]['value']: - ks_chart_data['labels'].append(res['x']) - ks_chart_data['domains'].append(res['domain']) - if self.ks_chart_measure_field_2 and self.ks_dashboard_item_type == 'ks_bar_chart': - ks_chart_data['ks_show_second_y_scale'] = True - values_2 = {'ks_sub_domain': {}} - series_2 = [] - for data in chart_sub_data: - label = data['labels'] - serie = data['series'] - series_2 = series_2 + serie - value = data['value'] - ks_sub_domain = data['domain'].copy() - - counter = 0 - for seri in serie: - if seri not in values_2: - values_2[seri] = {'ks_sub_domain': {}} - if label in values_2[seri]: - values_2[seri][label] = values_2[seri][label] + value[counter] - values_2[seri]['ks_sub_domain'][label] = ks_sub_domain - else: - values_2[seri][label] = value[counter] - values_2[seri]['ks_sub_domain'][label] = ks_sub_domain - counter += 1 - final_datasets_2 = [] - for serie in series_2: - if serie not in final_datasets_2: - final_datasets_2.append(serie) - ks_data_2 = [] - for dataset in final_datasets_2: - ks_dataset = { - 'value': [], - 'key': dataset - } - for label in xlabels: - ks_dataset['value'].append({ - 'x': label, - 'y': values_2[dataset][label] if label in values_2[dataset] else 0, - 'ks_sub_domain': values_2[dataset]['ks_sub_domain'][label] if values_2[dataset].get( - 'ks_sub_domain', False) and values_2[dataset]['ks_sub_domain'].get(label, - False) else [] - }) - ks_data_2.append(ks_dataset) - - for ks_dat in ks_data_2: - dataset = { - 'label': ks_dat['key'], - 'data': [], - 'type': 'line', - 'yAxisID': 'y-axis-1', - 'ks_sub_domain': [] - - } - for res in ks_dat['value']: - dataset['data'].append(res['y']) - dataset['ks_sub_domain'].append( - res['ks_sub_domain'] if res.get('ks_sub_domain', False) else []) - - ks_chart_data['datasets'].append(dataset) - for ks_dat in ks_data: - dataset = { - 'label': ks_dat['key'], - 'data': [], - 'ks_sub_domain': [] - } - for res in ks_dat['value']: - dataset['data'].append(res['y']) - dataset['ks_sub_domain'].append( - res['ks_sub_domain'] if res.get('ks_sub_domain', False) else []) - - ks_chart_data['datasets'].append(dataset) - - if self.ks_goal_enable and self.ks_standard_goal_value and self.ks_dashboard_item_type in [ - 'ks_bar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_horizontalBar_chart']: + try: + ks_goal_records = self.env['ks_dashboard_ninja.item_goal'].read_group( + ks_goal_domain, ['ks_goal_value'], + ['ks_goal_date' + ":" + ks_chart_date_groupby], lazy=False) + except: + ks_goal_records = [] + ks_goal_labels = [] + ks_goal_dataset = [] goal_dataset = [] - length = len(ks_chart_data['datasets'][0]['data']) - for _ in range(length): - goal_dataset.append(self.ks_standard_goal_value) + + if rec.ks_goal_lines and len(rec.ks_goal_lines) != 0: + ks_goal_domains = {} + for res in ks_goal_records: + if res['ks_goal_date' + ":" + ks_chart_date_groupby]: + ks_goal_labels.append(res['ks_goal_date' + ":" + ks_chart_date_groupby]) + ks_goal_dataset.append(res['ks_goal_value']) + ks_goal_domains[res['ks_goal_date' + ":" + ks_chart_date_groupby]] = res[ + '__domain'] + + for goal_domain in ks_goal_domains.keys(): + ks_goal_doamins = [] + for item in ks_goal_domains[goal_domain]: + + if 'ks_goal_date' in item: + domain = list(item) + domain[0] = ks_chart_groupby_relation_field + domain = tuple(domain) + ks_goal_doamins.append(domain) + ks_goal_doamins.insert(0, '&') + ks_goal_domains[goal_domain] = ks_goal_doamins + + domains = {} + counter = 0 + for label in ks_chart_data['labels']: + domains[label] = ks_chart_data['domains'][counter] + counter += 1 + + ks_chart_records_dates = ks_chart_data['labels'] + list( + set(ks_goal_labels) - set(ks_chart_data['labels'])) + + ks_chart_records = [] + for label in labels: + if label in ks_chart_records_dates: + ks_chart_records.append(label) + + ks_chart_data['domains'].clear() + datasets = [] + for dataset in ks_chart_data['datasets']: + datasets.append(dataset['data'].copy()) + + for dataset in ks_chart_data['datasets']: + dataset['data'].clear() + + for label in ks_chart_records: + domain = domains.get(label, False) + if domain: + ks_chart_data['domains'].append(domain) + else: + ks_chart_data['domains'].append(ks_goal_domains.get(label, [])) + counterr = 0 + if label in ks_chart_data['labels']: + index = ks_chart_data['labels'].index(label) + + for dataset in ks_chart_data['datasets']: + dataset['data'].append(datasets[counterr][index]) + counterr += 1 + + else: + for dataset in ks_chart_data['datasets']: + dataset['data'].append(0.00) + + if label in ks_goal_labels: + index = ks_goal_labels.index(label) + goal_dataset.append(ks_goal_dataset[index]) + else: + goal_dataset.append(0.00) + + ks_chart_data['labels'] = ks_chart_records + else: + if rec.ks_standard_goal_value: + length = len(ks_chart_data['datasets'][0]['data']) + for i in range(length): + goal_dataset.append(rec.ks_standard_goal_value) ks_goal_datasets = { 'label': 'Target', 'data': goal_dataset, 'ks_as_of_now': False } - if self.ks_goal_bar_line and self.ks_dashboard_item_type != 'ks_horizontalBar_chart': + if rec.ks_goal_bar_line: ks_goal_datasets['type'] = 'line' ks_chart_data['datasets'].insert(0, ks_goal_datasets) else: ks_chart_data['datasets'].append(ks_goal_datasets) - else: - ks_chart_data = False - if self.ks_multiplier_active: - for ks_multiplier in self.ks_multiplier_lines: - for i in range(0, len(ks_chart_data['datasets'])): + + elif rec.ks_chart_relation_sub_groupby and ((rec.ks_chart_sub_groupby_type == 'relational_type') or + (rec.ks_chart_sub_groupby_type == 'selection') or + (rec.ks_chart_sub_groupby_type == 'date_type' and + rec.ks_chart_date_sub_groupby) or + (rec.ks_chart_sub_groupby_type == 'other')): + if rec.ks_chart_relation_sub_groupby.ttype == 'date': + if rec.ks_chart_date_sub_groupby in ('minute', 'hour'): + raise ValidationError(_('Sub Groupby field: {} cannot be aggregated by {}').format( + rec.ks_chart_relation_sub_groupby.display_name, rec.ks_chart_date_sub_groupby)) + if rec.ks_chart_date_groupby in ('minute', 'hour'): + raise ValidationError(_('Groupby field: {} cannot be aggregated by {}').format( + rec.ks_chart_relation_sub_groupby.display_name, rec.ks_chart_date_groupby)) + # doesn't have time in date + ks_chart_date_sub_groupby = rec.ks_chart_date_sub_groupby + ks_chart_date_groupby = rec.ks_chart_date_groupby + else: + ks_chart_date_sub_groupby = rec.ks_chart_date_sub_groupby + if rec.ks_chart_date_groupby == 'month_year': + ks_chart_date_groupby = 'month' + else: + ks_chart_date_groupby = rec.ks_chart_date_groupby + if len(ks_chart_measure_field) != 0 or rec.ks_chart_data_count_type == 'count': + if rec.ks_chart_groupby_type == 'date_type' and ks_chart_date_groupby: + ks_chart_group = rec.ks_chart_relation_groupby.name + ":" + ks_chart_date_groupby + else: + ks_chart_group = rec.ks_chart_relation_groupby.name + + if rec.ks_chart_sub_groupby_type == 'date_type' and rec.ks_chart_date_sub_groupby: + ks_chart_sub_groupby_field = rec.ks_chart_relation_sub_groupby.name + ":" + \ + ks_chart_date_sub_groupby + else: + ks_chart_sub_groupby_field = rec.ks_chart_relation_sub_groupby.name + + ks_chart_groupby_relation_fields = [ks_chart_group, ks_chart_sub_groupby_field] + ks_chart_record = False try: - if ks_multiplier.ks_multiplier_fields.field_description in ks_chart_data['datasets'][i][ - 'label']: - data_values = ks_chart_data['datasets'][i]['data'] - data_values = list(map(lambda x: ks_multiplier.ks_multiplier_value * x, data_values)) - ks_chart_data['datasets'][i]['data'] = data_values - except Exception as e: - raise ValidationError('JSON file not supported.') + ks_chart_record = self.env[rec.ks_model_name].read_group(ks_chart_domain, + list(set( + ks_chart_measure_field_with_type + + ks_chart_measure_field_with_type_2 + + [ + ks_chart_groupby_relation_field, + rec.ks_chart_relation_sub_groupby.name])), + ks_chart_groupby_relation_fields,orderby=orderby, + limit=limit, + lazy=False) + except Exception: + ks_chart_record = {} + chart_data = [] + chart_sub_data = [] + for res in ks_chart_record: + domain = res.get('__domain', []) + if res.get(ks_chart_groupby_relation_fields[0], False): + if rec.ks_chart_groupby_type == 'date_type': + # x-axis modification + if rec.ks_chart_date_groupby == "day" \ + and rec.ks_chart_date_sub_groupby in ["quarter", "year"]: + label = " ".join(res[ks_chart_groupby_relation_fields[0]].split(" ")[0:2]) + elif rec.ks_chart_date_groupby in ["minute", "hour"] and \ + rec.ks_chart_date_sub_groupby in ["month", "week", "quarter", "year"]: + label = " ".join(res[ks_chart_groupby_relation_fields[0]].split(" ")[0:3]) + elif rec.ks_chart_date_groupby == 'month_year': + label = res[ks_chart_groupby_relation_fields[0]] + else: + label = res[ks_chart_groupby_relation_fields[0]].split(" ")[0] + elif rec.ks_chart_groupby_type == 'selection': + selection = res[ks_chart_groupby_relation_fields[0]] + label = dict(self.env[rec.ks_model_name].fields_get( + allfields=[ks_chart_groupby_relation_fields[0]]) + [ks_chart_groupby_relation_fields[0]]['selection'])[selection] + elif rec.ks_chart_groupby_type == 'relational_type': + label = res[ks_chart_groupby_relation_fields[0]][1] + elif rec.ks_chart_groupby_type == 'other': + label = res[ks_chart_groupby_relation_fields[0]] + labels = [] + value = [] + value_2 = [] + labels_2 = [] + if rec.ks_chart_data_count_type != 'count': + for ress in rec.ks_chart_measure_field: + if rec.ks_chart_sub_groupby_type == 'date_type': + if res[ks_chart_groupby_relation_fields[1]] is not False: + labels.append(res[ks_chart_groupby_relation_fields[1]].split(" ")[ + 0] + " " + ress.field_description) + else: + labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + " " + + ress.field_description) + elif rec.ks_chart_sub_groupby_type == 'selection': + if res[ks_chart_groupby_relation_fields[1]] is not False: + selection = res[ks_chart_groupby_relation_fields[1]] + labels.append(dict(self.env[rec.ks_model_name].fields_get( + allfields=[ks_chart_groupby_relation_fields[1]]) + [ks_chart_groupby_relation_fields[1]]['selection'])[ + selection] + + " " + ress.field_description) + else: + labels.append(str(res[ks_chart_groupby_relation_fields[1]])) + elif rec.ks_chart_sub_groupby_type == 'relational_type': + if res[ks_chart_groupby_relation_fields[1]] is not False: + labels.append(res[ks_chart_groupby_relation_fields[1]][1] + + " " + ress.field_description) + else: + labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + + " " + ress.field_description) + elif rec.ks_chart_sub_groupby_type == 'other': + if res[ks_chart_groupby_relation_fields[1]] is not False: + labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + + "\'s " + ress.field_description) + else: + labels.append(str(res[ks_chart_groupby_relation_fields[1]]) + + " " + ress.field_description) + + value.append(res.get( + ress.name, 0)) + + if rec.ks_chart_measure_field_2 and rec.ks_dashboard_item_type == 'ks_bar_chart': + for ress in rec.ks_chart_measure_field_2: + if rec.ks_chart_sub_groupby_type == 'date_type': + if res[ks_chart_groupby_relation_fields[1]] is not False: + labels_2.append( + res[ks_chart_groupby_relation_fields[1]].split(" ")[0] + " " + + ress.field_description) + else: + labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + + " " + ress.field_description) + elif rec.ks_chart_sub_groupby_type == 'selection': + selection = res[ks_chart_groupby_relation_fields[1]] + labels_2.append(dict(self.env[rec.ks_model_name].fields_get( + allfields=[ks_chart_groupby_relation_fields[1]]) + [ks_chart_groupby_relation_fields[1]][ + 'selection'])[ + selection] + " " + ress.field_description) + elif rec.ks_chart_sub_groupby_type == 'relational_type': + if res[ks_chart_groupby_relation_fields[1]] is not False: + labels_2.append( + res[ks_chart_groupby_relation_fields[1]][1] + " " + + ress.field_description) + else: + labels_2.append(str(res[ks_chart_groupby_relation_fields[1]]) + + " " + ress.field_description) + elif rec.ks_chart_sub_groupby_type == 'other': + labels_2.append(str( + res[ks_chart_groupby_relation_fields[1]]) + " " + + ress.field_description) + + value_2.append(res.get( + ress.name, 0)) + + chart_sub_data.append({ + 'value': value_2, + 'labels': label, + 'series': labels_2, + 'domain': domain, + }) + else: + if rec.ks_chart_sub_groupby_type == 'date_type': + if res[ks_chart_groupby_relation_fields[1]] is not False: + labels.append(res[ks_chart_groupby_relation_fields[1]].split(" ")[0]) + else: + labels.append(str(res[ks_chart_groupby_relation_fields[1]])) + elif rec.ks_chart_sub_groupby_type == 'selection': + selection = res[ks_chart_groupby_relation_fields[1]] + if selection: + labels.append(dict(self.env[rec.ks_model_name].fields_get( + allfields=[ks_chart_groupby_relation_fields[1]]) + [ks_chart_groupby_relation_fields[1]]['selection'])[ + selection]) + elif rec.ks_chart_sub_groupby_type == 'relational_type': + if res[ks_chart_groupby_relation_fields[1]] is not False: + labels.append(res[ks_chart_groupby_relation_fields[1]][1]) + else: + labels.append(str(res[ks_chart_groupby_relation_fields[1]])) + elif rec.ks_chart_sub_groupby_type == 'other': + labels.append(res[ks_chart_groupby_relation_fields[1]]) + value.append(res['__count']) + + chart_data.append({ + 'value': value, + 'labels': label, + 'series': labels, + 'domain': domain, + }) + + xlabels = [] + series = [] + values = {} + domains = {} + for data in chart_data: + label = data['labels'] + serie = data['series'] + domain = data['domain'] + + if (len(xlabels) == 0) or (label not in xlabels): + xlabels.append(label) + + if (label not in domains): + domains[label] = domain + else: + domains[label].insert(0, '|') + domains[label] = domains[label] + domain + + series = series + serie + value = data['value'] + counter = 0 + for seri in serie: + if seri not in values: + values[seri] = {} + if label in values[seri]: + values[seri][label] = values[seri][label] + value[counter] + else: + values[seri][label] = value[counter] + counter += 1 + + final_datasets = [] + for serie in series: + if serie not in final_datasets: + final_datasets.append(serie) + + ks_data = [] + for dataset in final_datasets: + ks_dataset = { + 'value': [], + 'key': dataset + } + for label in xlabels: + ks_dataset['value'].append({ + 'domain': domains[label], + 'x': label, + 'y': values[dataset][label] if label in values[dataset] else 0 + }) + ks_data.append(ks_dataset) + + if rec.ks_chart_relation_sub_groupby.name == rec.ks_chart_relation_groupby.name == rec.ks_sort_by_field.name: + ks_data = rec.ks_sort_sub_group_by_records(ks_data, rec.ks_chart_groupby_type, + rec.ks_chart_date_groupby, rec.ks_sort_by_order, + rec.ks_chart_date_sub_groupby) + + ks_chart_data = { + 'labels': [], + 'datasets': [], + 'domains': [], + 'ks_selection': "", + 'ks_currency': 0, + 'ks_field': "", + 'previous_domain': ks_chart_domain + } + + if rec.ks_unit and rec.ks_unit_selection == 'monetary': + ks_chart_data['ks_selection'] += rec.ks_unit_selection + ks_chart_data['ks_currency'] += rec.env.user.company_id.currency_id.id + elif rec.ks_unit and rec.ks_unit_selection == 'custom': + ks_chart_data['ks_selection'] += rec.ks_unit_selection + if rec.ks_chart_unit: + ks_chart_data['ks_field'] += rec.ks_chart_unit + + if len(ks_data) != 0: + for res in ks_data[0]['value']: + ks_chart_data['labels'].append(res['x']) + ks_chart_data['domains'].append(res['domain']) + if rec.ks_chart_measure_field_2 and rec.ks_dashboard_item_type == 'ks_bar_chart': + ks_chart_data['ks_show_second_y_scale'] = True + values_2 = {} + series_2 = [] + for data in chart_sub_data: + label = data['labels'] + serie = data['series'] + series_2 = series_2 + serie + value = data['value'] + + counter = 0 + for seri in serie: + if seri not in values_2: + values_2[seri] = {} + if label in values_2[seri]: + values_2[seri][label] = values_2[seri][label] + value[counter] + else: + values_2[seri][label] = value[counter] + counter += 1 + final_datasets_2 = [] + for serie in series_2: + if serie not in final_datasets_2: + final_datasets_2.append(serie) + ks_data_2 = [] + for dataset in final_datasets_2: + ks_dataset = { + 'value': [], + 'key': dataset + } + for label in xlabels: + ks_dataset['value'].append({ + 'x': label, + 'y': values_2[dataset][label] if label in values_2[dataset] else 0 + }) + ks_data_2.append(ks_dataset) + + for ks_dat in ks_data_2: + dataset = { + 'label': ks_dat['key'], + 'data': [], + 'type': 'line', + 'yAxisID': 'y-axis-1' + + } + for res in ks_dat['value']: + dataset['data'].append(res['y']) + + ks_chart_data['datasets'].append(dataset) + for ks_dat in ks_data: + dataset = { + 'label': ks_dat['key'], + 'data': [] + } + for res in ks_dat['value']: + dataset['data'].append(res['y']) + + ks_chart_data['datasets'].append(dataset) + + if rec.ks_goal_enable and rec.ks_standard_goal_value and rec.ks_dashboard_item_type in [ + 'ks_bar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_horizontalBar_chart']: + goal_dataset = [] + length = len(ks_chart_data['datasets'][0]['data']) + for i in range(length): + goal_dataset.append(rec.ks_standard_goal_value) + ks_goal_datasets = { + 'label': 'Target', + 'data': goal_dataset, + 'ks_as_of_now': False + } + if rec.ks_goal_bar_line and rec.ks_dashboard_item_type != 'ks_horizontalBar_chart': + ks_goal_datasets['type'] = 'line' + ks_chart_data['datasets'].insert(0, ks_goal_datasets) + else: + ks_chart_data['datasets'].append(ks_goal_datasets) + else: + ks_chart_data = False + if self.ks_multiplier_active: + for ks_multiplier in self.ks_multiplier_lines: + for i in range(0, len(ks_chart_data['datasets'])): + try: + if ks_multiplier.ks_multiplier_fields.field_description in ks_chart_data['datasets'][i][ + 'label']: + data_values = ks_chart_data['datasets'][i]['data'] + data_values = list(map(lambda x: ks_multiplier.ks_multiplier_value * x, data_values)) + ks_chart_data['datasets'][i]['data'] = data_values + except Exception as e: + raise ValidationError('JSON file not supported.') + if rec.ks_dashboard_item_type == 'ks_map_view' and ks_chart_data.get('groupByIds',False): + map_fields = ["partner_latitude", "partner_longitude", "name"] + map_domain = [['id', 'in',ks_chart_data['groupByIds']]] + ks_chart_data['partner'] = self.env['res.partner'].search_read(map_domain,map_fields) + if (rec.ks_partners_map): + ks_map_domain = [['id','in',json.loads(rec.ks_partners_map)]] + ks_chart_data['ks_partners_map'] = self.env['res.partner'].search_read(ks_map_domain,map_fields) + + return json.dumps(ks_chart_data) + else: + return False - return json.dumps(ks_chart_data) @api.depends('ks_domain', 'ks_dashboard_item_type', 'ks_pagination_limit', 'ks_model_id', 'ks_sort_by_field', 'ks_sort_by_order', 'ks_multiplier_active', 'ks_multiplier_lines', @@ -2923,7 +2875,7 @@ class KsDashboardNinjaItems(models.Model): self.ks_sort_by_field = orderid self.ks_sort_by_order = sort_order orderby = self.ks_sort_by_field.name if self.ks_sort_by_field else False - if self.ks_sort_by_order: + if orderby and self.ks_sort_by_order: orderby = orderby + " " + self.ks_sort_by_order if self.ks_list_view_type == "ungrouped": if self.ks_list_view_fields: @@ -2973,15 +2925,18 @@ class KsDashboardNinjaItems(models.Model): ks_list_view_data['list_view_type'] = 'date_type' ks_list_field = [] ks_chart_date_groupby = self.ks_chart_date_groupby + name = '' if self.ks_chart_date_groupby == 'month_year': ks_chart_date_groupby = 'month' + name = 'month_year' ks_list_view_data[ 'groupby'] = self.ks_chart_relation_groupby.name + ':' + ks_chart_date_groupby ks_list_field.append(self.ks_chart_relation_groupby.name) ks_list_fields.append(self.ks_chart_relation_groupby.name + ':' + ks_chart_date_groupby) ks_list_view_data['label'].append( - self.ks_chart_relation_groupby.field_description + ' : ' + ks_chart_date_groupby - .capitalize()) + self.ks_chart_relation_groupby.field_description + ' : ' + ( + 'Month-Year' if name == 'month_year' else ks_chart_date_groupby.capitalize()) + ) ks_list_view_data['fields'].append(self.ks_chart_relation_groupby.ids[0]) ks_list_view_data['fields_type'].append(self.ks_chart_relation_groupby.ttype) ks_list_view_data['store'].append(self.ks_chart_relation_groupby.store) @@ -3119,12 +3074,8 @@ class KsDashboardNinjaItems(models.Model): ks_list_view_data['store'].append(res.store) try: - if orderby: - group_by = [self.ks_chart_relation_groupby.name, orderby.split(' ')[0]] - else: - group_by = [self.ks_chart_relation_groupby.name] ks_list_view_records = self.env[self.ks_model_name] \ - .read_group(ks_chart_domain, ks_list_fields, group_by, + .read_group(ks_chart_domain, ks_list_fields, [self.ks_chart_relation_groupby.name], orderby=orderby, limit=limit, offset=ksoffset, lazy=False) except Exception as E: ks_list_view_records = [] @@ -3202,9 +3153,12 @@ class KsDashboardNinjaItems(models.Model): if ks_date_data['start_date'] and ks_date_data['end_date'] and rec.ks_goal_lines: labels = self.generate_timeserise(ks_date_data['start_date'], ks_date_data['end_date'], ks_chart_date_groupby) - ks_goal_records = self.env['ks_dashboard_ninja.item_goal'].read_group( - ks_goal_domain, ['ks_goal_value'], - ['ks_goal_date' + ":" + ks_chart_date_groupby], lazy=False) + try: + ks_goal_records = self.env['ks_dashboard_ninja.item_goal'].read_group( + ks_goal_domain, ['ks_goal_value'], + ['ks_goal_date' + ":" + ks_chart_date_groupby], lazy=False) + except: + ks_goal_records = [] ks_goal_labels = [] ks_goal_dataset = {} @@ -3315,8 +3269,8 @@ class KsDashboardNinjaItems(models.Model): 'data_rows': [], 'model': self.ks_model_name} # ks_chart_domain = self.ks_convert_into_proper_domain(self.ks_domain, self) - orderby = self.ks_sort_by_field.name if self.ks_sort_by_field else "id" - if self.ks_sort_by_order: + orderby = self.ks_sort_by_field.name if self.ks_sort_by_field else False + if orderby and self.ks_sort_by_order: orderby = orderby + " " + self.ks_sort_by_order ks_limit = self.ks_record_data_limit if self.ks_record_data_limit and self.ks_record_data_limit > 0 else False @@ -3382,9 +3336,9 @@ class KsDashboardNinjaItems(models.Model): for rec in self: if rec.ks_dashboard_item_type == "ks_bar_chart" or rec.ks_dashboard_item_type == "ks_horizontalBar_chart" \ or rec.ks_dashboard_item_type == "ks_line_chart" or rec.ks_dashboard_item_type == "ks_area_chart": - rec.ks_chart_item_color = "cool" + rec.ks_chart_item_color = "dark" else: - rec.ks_chart_item_color = "default" + rec.ks_chart_item_color = "moonrise" if rec.ks_dashboard_item_type == 'ks_kpi' or rec.ks_dashboard_item_type == 'ks_tile': rec.ks_data_calculation_type = 'custom' if rec.ks_dashboard_item_type != "ks_bar_chart": @@ -3752,23 +3706,13 @@ class KsDashboardNinjaItems(models.Model): [ks_chart_groupby_relation_field])), [ks_chart_groupby_field], orderby=orderby, limit=limit, lazy=False) else: - if orderby: - group_by=[ks_chart_groupby_field,orderby.split(' ')[0]] - else: - group_by = [ks_chart_groupby_field] ks_chart_records = self.env[ks_model_name] \ - .read_group(domain=ks_chart_domain, - fields=list(set(ks_chart_measure_field_with_type + ks_chart_measure_field_with_type_2 + - [ks_chart_groupby_relation_field])), groupby=group_by, + .read_group(ks_chart_domain, + list(set(ks_chart_measure_field_with_type + ks_chart_measure_field_with_type_2 + + [ks_chart_groupby_relation_field])), [ks_chart_groupby_field], orderby=orderby, limit=limit, lazy=False) except Exception as e: ks_chart_records = [] - print(e) # FIXME - # ks_chart_records = self.env[ks_model_name] \ - # .read_group(domain=ks_chart_domain, - # fields=list(set(ks_chart_measure_field_with_type + ks_chart_measure_field_with_type_2 + - # [ks_chart_groupby_relation_field])), groupby=[ks_chart_groupby_field], - # limit=limit, lazy=False) pass ks_chart_data['groupby'] = ks_chart_groupby_field if ks_chart_groupby_type == "relational_type": @@ -3895,6 +3839,8 @@ class KsDashboardNinjaItems(models.Model): ks_chart_type = action_line.ks_chart_type if action_line.ks_chart_type else record.ks_dashboard_item_type ks_list_view_data = {'label': [], 'type': 'grouped', 'data_rows': [], 'model': record.ks_model_name, 'previous_domain': domain, } + ks_action_name = action_line['ks_action_item_name'] + ks_action_id = action_line['id'] if action_line.ks_chart_type == 'ks_list_view': if record.ks_dashboard_item_type == 'ks_list_view': ks_chart_list_measure = record.ks_list_view_group_fields @@ -3904,7 +3850,7 @@ class KsDashboardNinjaItems(models.Model): ks_list_fields = [] # if action_line.ks_sort_by_field: # ks_list_fields.append(action_line.ks_sort_by_field.name) - orderby = action_line.ks_sort_by_field.name if action_line.ks_sort_by_field else "id" + orderby = action_line.ks_sort_by_field.name if action_line.ks_sort_by_field else False if action_line.ks_sort_by_order: orderby = orderby + " " + action_line.ks_sort_by_order limit = action_line.ks_record_limit \ @@ -3934,7 +3880,7 @@ class KsDashboardNinjaItems(models.Model): 'last_seq': ks_count, 'ks_column_type': []} for field_rec in ks_list_fields: if counter == 0: - data_row['data'].append(res[field_rec][1]._value if res[field_rec] else "False") + data_row['data'].append(res[field_rec][1] if res[field_rec] else "False") else: data_row['data'].append(res[field_rec]) counter += 1 @@ -4044,7 +3990,7 @@ class KsDashboardNinjaItems(models.Model): index] * ks_multiplier.ks_multiplier_value ks_list_view_data['data_rows'][i]['data'][index] = data_values return {"ks_list_view_data": json.dumps(ks_list_view_data), "ks_list_view_type": "grouped", - 'sequence': sequence + 1, } + 'sequence': sequence + 1, 'ks_action_name': "".join(ks_action_name.split(" "))} else: ks_chart_measure_field = [] ks_chart_measure_field_with_type = [] @@ -4106,7 +4052,7 @@ class KsDashboardNinjaItems(models.Model): if record.ks_chart_data_count_type == "count" and not self.ks_fill_temporal and not action_line.ks_sort_by_field: orderby = 'count' else: - orderby = action_line.ks_sort_by_field.name if action_line.ks_sort_by_field else "id" + orderby = action_line.ks_sort_by_field.name if action_line.ks_sort_by_field else False if action_line.ks_sort_by_order: orderby = orderby + " " + action_line.ks_sort_by_order limit = action_line.ks_record_limit if action_line.ks_record_limit and action_line.ks_record_limit > 0 else False @@ -4137,7 +4083,9 @@ class KsDashboardNinjaItems(models.Model): return { 'ks_chart_data': json.dumps(ks_chart_data), 'ks_chart_type': ks_chart_type, - 'sequence': sequence + 1, + 'ks_action_name': "".join(ks_action_name.split(" ")), + 'ks_action_id':ks_action_id, + 'sequence': sequence + 1 } @api.model @@ -4438,11 +4386,10 @@ class KsDashboardCsvGroupBy(models.Model): ks_dashboard_csv_group_by_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") name = fields.Char(string="Name") - ttype = fields.Selection([('char', 'char'), ('float', 'float'), + ttype = fields.Selection([('char', 'char'), ('date', 'date'), ('datetime', 'datetime'), ('float', 'float'), ('integer', 'integer')], string='Type') - class KsDashboardCsvNew(models.Model): _name = 'ks.dashboard.csv.new' _description = 'Dashboard Ninja New' @@ -4488,6 +4435,7 @@ class KsDashboardItemsActions(models.Model): "('ttype','!=','binary'),('ttype','!=','many2many'), " "('ttype','!=','one2many')]", string="Action Group By") + ks_action_item_name = fields.Char(string = "Action item name" ,compute="ks_check_special_character") ks_item_action_field_type = fields.Char(compute="ks_get_item_action_type", compute_sudo=False) @@ -4507,9 +4455,9 @@ class KsDashboardItemsActions(models.Model): ('ks_pie_chart', 'Pie Chart'), ('ks_doughnut_chart', 'Doughnut Chart'), ('ks_polarArea_chart', 'Polar Area Chart'), - ('ks_list_view', 'List View'), ('ks_radialBar_chart', 'Radial Bar Chart'), ('ks_scatter_chart', 'Scatter Chart'), + ('ks_list_view' , 'List View'), ('ks_radar_view', 'Radar View'), ('ks_flower_view', 'Flower View'), ('ks_funnel_chart', 'Funnel Chart'), @@ -4529,6 +4477,14 @@ class KsDashboardItemsActions(models.Model): ks_sort_by_order = fields.Selection([('ASC', 'Ascending'), ('DESC', 'Descending')], string="Sort Order") + @api.depends("ks_item_action_field") + def ks_check_special_character(self): + for rec in self: + if rec.ks_item_action_field: + rec.ks_action_item_name = "item"+str(rec.sequence) + else: + rec.ks_action_item_name = "none" + @api.depends('ks_item_action_field') def ks_get_item_action_type(self): for rec in self: @@ -4567,4 +4523,8 @@ class KsDashboardItemMultiplier(models.Model): "('store','=',True),'|','|'," "('ttype','=','integer'),('ttype','=','float')," "('ttype','=','monetary')]", - string="Multiplier Field") \ No newline at end of file + string="Multiplier Field") + + + + ## in labels ._value is not working #### \ No newline at end of file diff --git a/ks_dashboard_ninja/models/ks_dn_to_do_item.py b/ks_dashboard_ninja/models/ks_dn_to_do_item.py index bbb27c1fd..78eaa1376 100644 --- a/ks_dashboard_ninja/models/ks_dn_to_do_item.py +++ b/ks_dashboard_ninja/models/ks_dn_to_do_item.py @@ -19,55 +19,93 @@ class KsDashboardNinjaItems(models.Model): ks_to_do_data = rec._ksGetToDOData() rec.ks_to_do_data = ks_to_do_data - def getToDoData(self): - return self._ksGetToDOData() - def _ksGetToDOData(self): - """ @return ks_to_do_data = { - "items":[ - {"item_id": item_id1, "label": label1, "lines": [{"id": id1, "content": content1, "active": active},{"id": id2, "content": content1, "active": active}] , - {"item_id": item_id2,"label": label2,"lines": [{"id": id3, "content": content2, "active": active},...], - ] + 'label': [], + 'ks_link': [], + 'ks_href_id': [], + 'ks_section_id': [], + 'ks_content': {}, + 'ks_content_record_id': {}, + 'ks_content_active': {} } - """ + if self.ks_dn_header_lines: + for ks_dn_header_line in self.ks_dn_header_lines: + ks_to_do_header_label = ks_dn_header_line.ks_to_do_header[:] + ks_to_do_data['label'].append(ks_to_do_header_label) + ks_dn_header_line_id = str(ks_dn_header_line.id) + if type(ks_dn_header_line.id).__name__ != 'int' and ks_dn_header_line.id.ref != None: + ks_dn_header_line_id = ks_dn_header_line.id.ref + if ' ' in ks_dn_header_line.ks_to_do_header: + ks_temp = ks_dn_header_line.ks_to_do_header.replace(" ", "") + ks_to_do_data['ks_link'].append('#' + ks_temp + ks_dn_header_line_id) + ks_to_do_data['ks_href_id'].append(ks_temp + str(ks_dn_header_line.id)) - if not self.ks_dn_header_lines: - return False - ks_to_do_data = { - 'items': [], - } - items = [] - for record in self.ks_dn_header_lines: - lines = [] - for line in record.ks_to_do_description_lines: - if isinstance(line.id, int): - line_id = line.id + elif ks_dn_header_line.ks_to_do_header[0].isdigit(): + ks_temp = ks_dn_header_line.ks_to_do_header.replace( + ks_dn_header_line.ks_to_do_header[0], 'z') + ks_to_do_data['ks_link'].append('#' + ks_temp + ks_dn_header_line_id) + ks_to_do_data['ks_href_id'].append(ks_temp + str(ks_dn_header_line.id)) else: - try: - line_id = line.ids[0] - except IndexError: - line_id = 0 - lines.append({ - "id": line_id, - "ks_description": line.ks_description, - "ks_active": line.ks_active - }) - if isinstance(record.id, int): - record_id = record.id - else: - try: - record_id = record.ids[0] - except IndexError: - record_id = 0 - items.append({ - "item_id": record_id, - "label": record.ks_to_do_header, - "lines": lines - }) - ks_to_do_data['items'] = items - return json.dumps(ks_to_do_data) + ks_to_do_data['ks_link'].append('#' + ks_dn_header_line.ks_to_do_header + ks_dn_header_line_id) + ks_to_do_data['ks_href_id'].append(ks_dn_header_line.ks_to_do_header + str(ks_dn_header_line.id)) + ks_to_do_data['ks_section_id'].append(str(ks_dn_header_line.id)) + if len(ks_dn_header_line.ks_to_do_description_lines): + for ks_to_do_description_line in ks_dn_header_line.ks_to_do_description_lines: + if ' ' in ks_dn_header_line.ks_to_do_header or ks_dn_header_line.ks_to_do_header[0].isdigit(): + if ks_to_do_data['ks_content'].get(ks_temp + + str(ks_dn_header_line.id), False): + + ks_to_do_data['ks_content'][ks_temp + + str(ks_dn_header_line.id)].append( + ks_to_do_description_line.ks_description) + ks_to_do_data['ks_content_record_id'][ks_temp + + str(ks_dn_header_line.id)].append( + str(ks_to_do_description_line.id)) + ks_to_do_data['ks_content_active'][ks_temp + + str(ks_dn_header_line.id)].append( + str(ks_to_do_description_line.ks_active)) + else: + ks_to_do_data['ks_content'][ks_temp + + str(ks_dn_header_line.id)] = [ + ks_to_do_description_line.ks_description] + ks_to_do_data['ks_content_record_id'][ks_temp + + str(ks_dn_header_line.id)] = [ + str(ks_to_do_description_line.id)] + ks_to_do_data['ks_content_active'][ks_temp + + str(ks_dn_header_line.id)] = [ + str(ks_to_do_description_line.ks_active)] + else: + if ks_to_do_data['ks_content'].get(ks_dn_header_line.ks_to_do_header + + str(ks_dn_header_line.id), False): + + ks_to_do_data['ks_content'][ks_dn_header_line.ks_to_do_header + + str(ks_dn_header_line.id)].append( + ks_to_do_description_line.ks_description) + ks_to_do_data['ks_content_record_id'][ks_dn_header_line.ks_to_do_header + + str(ks_dn_header_line.id)].append( + str(ks_to_do_description_line.id)) + ks_to_do_data['ks_content_active'][ks_dn_header_line.ks_to_do_header + + str(ks_dn_header_line.id)].append( + str(ks_to_do_description_line.ks_active)) + else: + ks_to_do_data['ks_content'][ks_dn_header_line.ks_to_do_header + + str(ks_dn_header_line.id)] = [ + ks_to_do_description_line.ks_description] + ks_to_do_data['ks_content_record_id'][ks_dn_header_line.ks_to_do_header + + str(ks_dn_header_line.id)] = [ + str(ks_to_do_description_line.id)] + ks_to_do_data['ks_content_active'][ks_dn_header_line.ks_to_do_header + + str(ks_dn_header_line.id)] = [ + str(ks_to_do_description_line.ks_active)] + + ks_to_do_data = json.dumps(ks_to_do_data) + else: + ks_to_do_data = False + return ks_to_do_data + + class KsToDoheaders(models.Model): diff --git a/ks_dashboard_ninja/models/res_settings.py b/ks_dashboard_ninja/models/res_settings.py index 3f884c2ba..7b1423467 100644 --- a/ks_dashboard_ninja/models/res_settings.py +++ b/ks_dashboard_ninja/models/res_settings.py @@ -11,7 +11,7 @@ class ResConfig(models.TransientModel): url = fields.Char(string="URL", store=True, config_parameter="ks_dashboard_ninja.url") ks_email_id = fields.Char(string="Email ID",store=True,config_parameter="ks_dashboard_ninja.ks_email_id") - + ks_analysis_word_length = fields.Selection([("50","50 words"),("100","100 words"),("150","150 words"),("200","200 words"),],default ="100", string="AI Analysis length", store=True,config_parameter="ks_dashboard_ninja.ks_analysis_word_length") def Open_wizard(self): if self.url and self.ks_email_id: try: @@ -42,9 +42,9 @@ class ResConfig(models.TransientModel): raise ValidationError( _("key already generated.If you need assistance, feel free to contact at sales@ksolves.com")) else: - raise ValidationError(_("Some problem in sending request. If you need assistance, feel free to contact at sales@ksolves.com")) + raise ValidationError(_("Either you have entered wrong URL path or there is some problem in sending request. If you need assistance, feel free to contact at sales@ksolves.com")) else: - raise ValidationError(_("Either you have entered wrong URL path or there is some problem in sending request. If you need assistance, feel free to contact at sales@ksolves.com")) + raise ValidationError(_("Some problem in sending request.Please contact at sales@ksolves.com")) else: raise ValidationError(_("Please enter URL and Email ID")) diff --git a/ks_dashboard_ninja/requirements.txt b/ks_dashboard_ninja/requirements.txt index 8a7a97536..b3a8c904c 100644 --- a/ks_dashboard_ninja/requirements.txt +++ b/ks_dashboard_ninja/requirements.txt @@ -1,2 +1,4 @@ pandas==2.0.3 -xlrd==1.2.0 \ No newline at end of file +xlrd==2.0.1 +openpyxl == 3.1.2 +gTTS == 2.5.1 \ No newline at end of file diff --git a/ks_dashboard_ninja/security/ir.model.access.csv b/ks_dashboard_ninja/security/ir.model.access.csv index 99a27a971..b07cf6702 100644 --- a/ks_dashboard_ninja/security/ir.model.access.csv +++ b/ks_dashboard_ninja/security/ir.model.access.csv @@ -1,35 +1,35 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_ks_dashboard_ninja_board,ks_dashboard_ninja.board,model_ks_dashboard_ninja_board,,1,1,1,1 -access_ks_dashboard_ninja_kpi_mail,ks_dashboard_ninja.kpi_mail,model_ks_dashboard_ninja_kpi_mail,,1,1,1,1 -access_ks_dashboard_ninja_item,ks_dashboard_ninja.item,model_ks_dashboard_ninja_item,,1,1,1,1 -access_ks_to_do_headers,ks_to.do.headers,model_ks_to_do_headers,,1,1,1,1 -access_ks_to_do_description,ks_to.do.description,model_ks_to_do_description,,1,1,1,1 -access_ks_dashboard_ninja_child_board,ks_dashboard_ninja.child_board,model_ks_dashboard_ninja_child_board,,1,1,1,1 -access_ks_dashboard_ninja_board_defined_filters,ks_dashboard_ninja.board_defined_filters,model_ks_dashboard_ninja_board_defined_filters,,1,1,1,1 -access_ks_dashboard_ninja_board_custom_filters,ks_dashboard_ninja.board_custom_filters,model_ks_dashboard_ninja_board_custom_filters,,1,1,1,1 +access_ks_dashboard_ninja_board,ks_dashboard_ninja.board,model_ks_dashboard_ninja_board,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_kpi_mail,ks_dashboard_ninja.kpi_mail,model_ks_dashboard_ninja_kpi_mail,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_item,ks_dashboard_ninja.item,model_ks_dashboard_ninja_item,base.group_user,1,1,1,1 +access_ks_to_do_headers,ks_to.do.headers,model_ks_to_do_headers,base.group_user,1,1,1,1 +access_ks_to_do_description,ks_to.do.description,model_ks_to_do_description,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_child_board,ks_dashboard_ninja.child_board,model_ks_dashboard_ninja_child_board,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_board_defined_filters,ks_dashboard_ninja.board_defined_filters,model_ks_dashboard_ninja_board_defined_filters,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_board_custom_filters,ks_dashboard_ninja.board_custom_filters,model_ks_dashboard_ninja_board_custom_filters,base.group_user,1,1,1,1 -access_ks_dashboard_ninja_board_template,ks_dashboard_ninja.board_template,model_ks_dashboard_ninja_board_template,,1,1,1,1 -access_ks_dashboard_ninja_item_goal,ks_dashboard_ninja_item_goal,model_ks_dashboard_ninja_item_goal,,1,1,1,1 -access_ks_dashboard_ninja_item_action,ks_dashboard_ninja_item_action,model_ks_dashboard_ninja_item_action,,1,1,1,1 -access_ks_dashboard_item_multiplier,ks_dashboard_item.multiplier,model_ks_dashboard_item_multiplier,,1,1,1,1 -access_ks_ninja_dashboard_item_action,ks_ninja_dashboard.item_action,model_ks_ninja_dashboard_item_action,,1,1,1,0 -access_ks_dashboard_group_by,ks.dashboard.group.by,model_ks_dashboard_group_by,,1,1,1,1 -access_ks_dashboard_csv_group_by,ks.dashboard.csv.group.by,model_ks_dashboard_csv_group_by,,1,1,1,1 -access_ks_dashboard_new,ks.dashboard.new,model_ks_dashboard_new,,1,1,1,1 -access_ks_dashboard_csv_new,ks.dashboard.csv.new,model_ks_dashboard_csv_new,,1,1,1,1 +access_ks_dashboard_ninja_board_template,ks_dashboard_ninja.board_template,model_ks_dashboard_ninja_board_template,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_item_goal,ks_dashboard_ninja_item_goal,model_ks_dashboard_ninja_item_goal,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_item_action,ks_dashboard_ninja_item_action,model_ks_dashboard_ninja_item_action,base.group_user,1,1,1,1 +access_ks_dashboard_item_multiplier,ks_dashboard_item.multiplier,model_ks_dashboard_item_multiplier,base.group_user,1,1,1,1 +access_ks_ninja_dashboard_item_action,ks_ninja_dashboard.item_action,model_ks_ninja_dashboard_item_action,base.group_user,1,1,1,0 +access_ks_dashboard_group_by,ks.dashboard.group.by,model_ks_dashboard_group_by,base.group_user,1,1,1,1 +access_ks_dashboard_csv_group_by,ks.dashboard.csv.group.by,model_ks_dashboard_csv_group_by,base.group_user,1,1,1,1 +access_ks_dashboard_new,ks.dashboard.new,model_ks_dashboard_new,base.group_user,1,1,1,1 +access_ks_dashboard_csv_new,ks.dashboard.csv.new,model_ks_dashboard_csv_new,base.group_user,1,1,1,1 access_ks_dashboard_ninja_import,ks_dashboard_ninja.import,model_ks_dashboard_ninja_import,base.group_system,1,1,1,0 -access_ir_actions_act_window_view,ir.actions.act_window.view,base.model_ir_actions_act_window_view,,1,0,0,0 -access_ir_actions_act_window,ir.actions.act_window,base.model_ir_actions_act_window,,1,0,0,0 -access_ir_actions_client,ir.actions.client,base.model_ir_actions_client,,1,0,0,0 -access_ir_ui_menu,ir.ui.menu,base.model_ir_ui_menu,,1,1,0,0 +access_ir_actions_act_window_view,ir.actions.act_window.view,base.model_ir_actions_act_window_view,base.group_user,1,0,0,0 +access_ir_actions_act_window,ir.actions.act_window,base.model_ir_actions_act_window,base.group_user,1,0,0,0 +access_ir_actions_client,ir.actions.client,base.model_ir_actions_client,base.group_user,1,0,0,0 +access_ir_ui_menu,ir.ui.menu,base.model_ir_ui_menu,base.group_user,1,1,0,0 access_ir_model_group_user,ir.model,base.model_ir_model,base.group_user,1,0,0,0 access_ir_model_fields_group_user,ir.model.fields,base.model_ir_model_fields,base.group_user,1,0,0,0 -access_ir_model_ks_dashboard_wizard,ks_dashboard_wizard,model_ks_dashboard_wizard,,1,1,1,1 -access_ir_model_ks_duplicate_dashboard_wizard,ks_duplicate_dashboard__wizard,model_ks_dashboard_duplicate_wizard,,1,1,1,1 -access_ir_model_ks_delete_dashboard_wizard,ks_delete_dashboard__wizard,model_ks_dashboard_delete_wizard,,1,1,1,1 -access_ks_dashboard_ninja_arti_int,ks_dashboard_ninja.arti_int,model_ks_dashboard_ninja_arti_int,,1,1,1,1 -access_ks_dashboard_ninja_ai_dashboard,ks_dashboard_ninja.ai_dashboard,model_ks_dashboard_ninja_ai_dashboard,,1,1,1,1 -access_ks_dashboard_ninja_fetch_key,ks_dashboard_ninja.fetch_key,model_ks_dashboard_ninja_fetch_key,,1,1,1,1 \ No newline at end of file +access_ir_model_ks_dashboard_wizard,ks_dashboard_wizard,model_ks_dashboard_wizard,base.group_user,1,1,1,1 +access_ir_model_ks_duplicate_dashboard_wizard,ks_duplicate_dashboard__wizard,model_ks_dashboard_duplicate_wizard,base.group_user,1,1,1,1 +access_ir_model_ks_delete_dashboard_wizard,ks_delete_dashboard__wizard,model_ks_dashboard_delete_wizard,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_arti_int,ks_dashboard_ninja.arti_int,model_ks_dashboard_ninja_arti_int,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_ai_dashboard,ks_dashboard_ninja.ai_dashboard,model_ks_dashboard_ninja_ai_dashboard,base.group_user,1,1,1,1 +access_ks_dashboard_ninja_fetch_key,ks_dashboard_ninja.fetch_key,model_ks_dashboard_ninja_fetch_key,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/ks_dashboard_ninja/static/description/DN_with_AI.gif b/ks_dashboard_ninja/static/description/DN_with_AI.gif new file mode 100644 index 000000000..34b34c0c7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/DN_with_AI.gif differ diff --git a/ks_dashboard_ninja/static/description/Dashboard Ninja with AI.gif b/ks_dashboard_ninja/static/description/Dashboard Ninja with AI.gif new file mode 100644 index 000000000..773d535d4 Binary files /dev/null and b/ks_dashboard_ninja/static/description/Dashboard Ninja with AI.gif differ diff --git a/ks_dashboard_ninja/static/description/Financial Year End sale.gif b/ks_dashboard_ninja/static/description/Financial Year End sale.gif new file mode 100644 index 000000000..27ee99340 Binary files /dev/null and b/ks_dashboard_ninja/static/description/Financial Year End sale.gif differ diff --git a/ks_dashboard_ninja/static/description/Flag day.gif b/ks_dashboard_ninja/static/description/Flag day.gif new file mode 100644 index 000000000..034019f53 Binary files /dev/null and b/ks_dashboard_ninja/static/description/Flag day.gif differ diff --git a/ks_dashboard_ninja/static/description/Independence_sale.jpg b/ks_dashboard_ninja/static/description/Independence_sale.jpg new file mode 100644 index 000000000..8604326dc Binary files /dev/null and b/ks_dashboard_ninja/static/description/Independence_sale.jpg differ diff --git a/ks_dashboard_ninja/static/description/On Dashboard Ninja & Dashboard Ninja Advance.gif b/ks_dashboard_ninja/static/description/On Dashboard Ninja & Dashboard Ninja Advance.gif new file mode 100644 index 000000000..028791b4e Binary files /dev/null and b/ks_dashboard_ninja/static/description/On Dashboard Ninja & Dashboard Ninja Advance.gif differ diff --git a/ks_dashboard_ninja/static/description/ai-img/1.png b/ks_dashboard_ninja/static/description/ai-img/1.png new file mode 100644 index 000000000..0c00e0d44 Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/1.png differ diff --git a/ks_dashboard_ninja/static/description/ai-img/bg-img-ai.png b/ks_dashboard_ninja/static/description/ai-img/bg-img-ai.png new file mode 100644 index 000000000..c4152d909 Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/bg-img-ai.png differ diff --git a/ks_dashboard_ninja/static/description/ai-img/dashboard_with_AI.png b/ks_dashboard_ninja/static/description/ai-img/dashboard_with_AI.png new file mode 100644 index 000000000..4016afa7f Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/dashboard_with_AI.png differ diff --git a/ks_dashboard_ninja/static/description/ai-img/o1.png b/ks_dashboard_ninja/static/description/ai-img/o1.png new file mode 100644 index 000000000..a22868b97 Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/o1.png differ diff --git a/ks_dashboard_ninja/static/description/ai-img/o2.png b/ks_dashboard_ninja/static/description/ai-img/o2.png new file mode 100644 index 000000000..1b92ea09a Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/o2.png differ diff --git a/ks_dashboard_ninja/static/description/ai-img/o3.png b/ks_dashboard_ninja/static/description/ai-img/o3.png new file mode 100644 index 000000000..ab332f795 Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/o3.png differ diff --git a/ks_dashboard_ninja/static/description/ai-img/odoo-Dashboard-Ninja.png b/ks_dashboard_ninja/static/description/ai-img/odoo-Dashboard-Ninja.png new file mode 100644 index 000000000..50dc22b27 Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/odoo-Dashboard-Ninja.png differ diff --git a/ks_dashboard_ninja/static/description/ai-img/top-logo-1.png b/ks_dashboard_ninja/static/description/ai-img/top-logo-1.png new file mode 100644 index 000000000..e50643dc9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/ai-img/top-logo-1.png differ diff --git a/ks_dashboard_ninja/static/description/banner.gif b/ks_dashboard_ninja/static/description/banner.gif new file mode 100644 index 000000000..f011d7651 Binary files /dev/null and b/ks_dashboard_ninja/static/description/banner.gif differ diff --git a/ks_dashboard_ninja/static/description/css/bootstrap.min.css b/ks_dashboard_ninja/static/description/css/bootstrap.min.css new file mode 100644 index 000000000..6ee59568c --- /dev/null +++ b/ks_dashboard_ninja/static/description/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-sm-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-sm-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-md-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-md-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-md-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-md-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-md-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-md-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-lg-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-lg-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-xl-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-xl-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#b3b7bb}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{-webkit-appearance:none;-moz-appearance:none;appearance:none}select.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:1rem;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.form-row>.col>.valid-tooltip,.form-row>[class*=col-]>.valid-tooltip{left:5px}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#28a745;padding-right:calc(1.5em + .75rem)!important;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.was-validated select.form-control:valid,select.form-control.is-valid{padding-right:3rem!important;background-position:right 1.5rem center}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#28a745;padding-right:calc(.75em + 2.3125rem)!important;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") right .75rem center/8px 10px no-repeat,#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#28a745}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#34ce57;background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.form-row>.col>.invalid-tooltip,.form-row>[class*=col-]>.invalid-tooltip{left:5px}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem)!important;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.was-validated select.form-control:invalid,select.form-control.is-invalid{padding-right:3rem!important;background-position:right 1.5rem center}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#dc3545;padding-right:calc(.75em + 2.3125rem)!important;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") right .75rem center/8px 10px no-repeat,#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#dc3545}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#e4606d;background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#0069d9;border-color:#0062cc;box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{color:#fff;background-color:#5a6268;border-color:#545b62;box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#218838;border-color:#1e7e34;box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#138496;border-color:#117a8b;box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{color:#212529;background-color:#e0a800;border-color:#d39e00;box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c82333;border-color:#bd2130;box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{color:#212529;background-color:#e2e6ea;border-color:#dae0e5;box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{color:#fff;background-color:#23272b;border-color:#1d2124;box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;min-width:0;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label,.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label::after,.input-group:not(.has-validation)>.custom-select:not(:last-child),.input-group:not(.has-validation)>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label,.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label::after,.input-group.has-validation>.custom-select:nth-last-child(n+3),.input-group.has-validation>.form-control:nth-last-child(n+3){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.btn,.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.input-group-text,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.btn,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;z-index:1;display:block;min-height:1.5rem;padding-left:1.5rem;-webkit-print-color-adjust:exact;color-adjust:exact}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.25rem;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before,.custom-control-input[disabled]~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#fff;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:50%/50% 50% no-repeat}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") right .75rem center/8px 10px no-repeat;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;overflow:hidden;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;overflow:hidden;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{-moz-transition:none;transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;-ms-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{-ms-transition:none;transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item,.nav-fill>.nav-link{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:50%/100% 100% no-repeat}.navbar-nav-scroll{max-height:75vh;overflow-y:auto}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{-ms-flex-negative:0;flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{-ms-flex:1 0 0%;flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion{overflow-anchor:none}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#0062cc}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.badge-secondary{color:#fff;background-color:#6c757d}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#545b62}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.badge-success{color:#fff;background-color:#28a745}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#1e7e34}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#117a8b}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#212529;background-color:#d39e00}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#bd2130}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:focus,a.badge-light:hover{color:#212529;background-color:#dae0e5}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:focus,a.badge-dark:hover{color:#fff;background-color:#1d2124}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;z-index:2;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{-ms-flex-preferred-size:350px;flex-basis:350px;max-width:350px;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal.modal-static .modal-dialog{-webkit-transform:scale(1.02);transform:scale(1.02)}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);height:-webkit-min-content;height:-moz-min-content;height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem);height:-webkit-min-content;height:-moz-min-content;height:min-content}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:50%/100% 100% no-repeat}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;-ms-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;word-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/ks_dashboard_ninja/static/description/dn_v16_optimize.gif b/ks_dashboard_ninja/static/description/dn_v16_optimize.gif new file mode 100644 index 000000000..0ba31f85f Binary files /dev/null and b/ks_dashboard_ninja/static/description/dn_v16_optimize.gif differ diff --git a/ks_dashboard_ninja/static/description/icon.png b/ks_dashboard_ninja/static/description/icon.png index 34ebc7395..8936299f0 100644 Binary files a/ks_dashboard_ninja/static/description/icon.png and b/ks_dashboard_ninja/static/description/icon.png differ diff --git a/ks_dashboard_ninja/static/description/img/2-list-view-img.png b/ks_dashboard_ninja/static/description/img/2-list-view-img.png new file mode 100644 index 000000000..395985cac Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/2-list-view-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/Authentic_Mycompany_Filter.png b/ks_dashboard_ninja/static/description/img/Authentic_Mycompany_Filter.png new file mode 100644 index 000000000..651b824d9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Authentic_Mycompany_Filter.png differ diff --git a/ks_dashboard_ninja/static/description/img/Community_Enterprise_Odoosh_Support.png b/ks_dashboard_ninja/static/description/img/Community_Enterprise_Odoosh_Support.png new file mode 100644 index 000000000..ba2ad8d89 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Community_Enterprise_Odoosh_Support.png differ diff --git a/ks_dashboard_ninja/static/description/img/Community_Enterprise_Odoosh_Support_BG.png b/ks_dashboard_ninja/static/description/img/Community_Enterprise_Odoosh_Support_BG.png new file mode 100644 index 000000000..e3f8e9279 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Community_Enterprise_Odoosh_Support_BG.png differ diff --git a/ks_dashboard_ninja/static/description/img/Dashboard_Personalization_Configuration_BG.png b/ks_dashboard_ninja/static/description/img/Dashboard_Personalization_Configuration_BG.png new file mode 100644 index 000000000..d9a63e8fd Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Dashboard_Personalization_Configuration_BG.png differ diff --git a/ks_dashboard_ninja/static/description/img/Design_Multiple_Dashboard.gif b/ks_dashboard_ninja/static/description/img/Design_Multiple_Dashboard.gif new file mode 100644 index 000000000..c006401bf Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Design_Multiple_Dashboard.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Design_your_Dashbaord.gif b/ks_dashboard_ninja/static/description/img/Design_your_Dashbaord.gif new file mode 100644 index 000000000..ffd26d271 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Design_your_Dashbaord.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Design_your_own_Dashboard.gif b/ks_dashboard_ninja/static/description/img/Design_your_own_Dashboard.gif new file mode 100644 index 000000000..57afe284b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Design_your_own_Dashboard.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Design_your_own_Dashboard_Layout_BG.png b/ks_dashboard_ninja/static/description/img/Design_your_own_Dashboard_Layout_BG.png new file mode 100644 index 000000000..38209dc1b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Design_your_own_Dashboard_Layout_BG.png differ diff --git a/ks_dashboard_ninja/static/description/img/Drill_Down_Drill_UP.gif b/ks_dashboard_ninja/static/description/img/Drill_Down_Drill_UP.gif new file mode 100644 index 000000000..1670ee946 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Drill_Down_Drill_UP.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Duplicate_Move.gif b/ks_dashboard_ninja/static/description/img/Duplicate_Move.gif new file mode 100644 index 000000000..10281b271 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Duplicate_Move.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Dynamic_Animated.gif b/ks_dashboard_ninja/static/description/img/Dynamic_Animated.gif new file mode 100644 index 000000000..42bd3d84c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Dynamic_Animated.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Group 2315.png b/ks_dashboard_ninja/static/description/img/Group 2315.png new file mode 100644 index 000000000..83c3ee7a9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Group 2315.png differ diff --git a/ks_dashboard_ninja/static/description/img/Group 2316.png b/ks_dashboard_ninja/static/description/img/Group 2316.png new file mode 100644 index 000000000..0818fbc24 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Group 2316.png differ diff --git a/ks_dashboard_ninja/static/description/img/Group 2317.png b/ks_dashboard_ninja/static/description/img/Group 2317.png new file mode 100644 index 000000000..c3616f49c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Group 2317.png differ diff --git a/ks_dashboard_ninja/static/description/img/Info-circle.svg b/ks_dashboard_ninja/static/description/img/Info-circle.svg new file mode 100644 index 000000000..fbe9d9caa --- /dev/null +++ b/ks_dashboard_ninja/static/description/img/Info-circle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ks_dashboard_ninja/static/description/img/Instant_Edit_Mode.gif b/ks_dashboard_ninja/static/description/img/Instant_Edit_Mode.gif new file mode 100644 index 000000000..ac59878d2 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Instant_Edit_Mode.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Instant_Edit_Mode_BG.png b/ks_dashboard_ninja/static/description/img/Instant_Edit_Mode_BG.png new file mode 100644 index 000000000..f13a186c1 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Instant_Edit_Mode_BG.png differ diff --git a/ks_dashboard_ninja/static/description/img/Monesty_Custom_Units.gif b/ks_dashboard_ninja/static/description/img/Monesty_Custom_Units.gif new file mode 100644 index 000000000..ea781a669 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Monesty_Custom_Units.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Monetary_Custom_Units_BG.png b/ks_dashboard_ninja/static/description/img/Monetary_Custom_Units_BG.png new file mode 100644 index 000000000..0bd8268a1 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Monetary_Custom_Units_BG.png differ diff --git a/ks_dashboard_ninja/static/description/img/Multi_Color_Themes.png b/ks_dashboard_ninja/static/description/img/Multi_Color_Themes.png new file mode 100644 index 000000000..8c2505711 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Multi_Color_Themes.png differ diff --git a/ks_dashboard_ninja/static/description/img/Number_System.gif b/ks_dashboard_ninja/static/description/img/Number_System.gif new file mode 100644 index 000000000..e5bef87e2 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Number_System.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Number_Systems.png b/ks_dashboard_ninja/static/description/img/Number_Systems.png new file mode 100644 index 000000000..db11f21c4 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Number_Systems.png differ diff --git a/ks_dashboard_ninja/static/description/img/Progress.svg b/ks_dashboard_ninja/static/description/img/Progress.svg new file mode 100644 index 000000000..4de1f3895 --- /dev/null +++ b/ks_dashboard_ninja/static/description/img/Progress.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/ks_dashboard_ninja/static/description/img/RTL_Support_BG.png b/ks_dashboard_ninja/static/description/img/RTL_Support_BG.png new file mode 100644 index 000000000..e9f01784c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/RTL_Support_BG.png differ diff --git a/ks_dashboard_ninja/static/description/img/Real_Time_Streaming.gif b/ks_dashboard_ninja/static/description/img/Real_Time_Streaming.gif new file mode 100644 index 000000000..64600bae7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Real_Time_Streaming.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Rectangle 1641.png b/ks_dashboard_ninja/static/description/img/Rectangle 1641.png new file mode 100644 index 000000000..1d0271ec3 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Rectangle 1641.png differ diff --git a/ks_dashboard_ninja/static/description/img/Show_Hide_Data.gif b/ks_dashboard_ninja/static/description/img/Show_Hide_Data.gif new file mode 100644 index 000000000..b662b1858 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Show_Hide_Data.gif differ diff --git a/ks_dashboard_ninja/static/description/img/Show_Hide_Data_Values.png b/ks_dashboard_ninja/static/description/img/Show_Hide_Data_Values.png new file mode 100644 index 000000000..d303a6126 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/Show_Hide_Data_Values.png differ diff --git a/ks_dashboard_ninja/static/description/img/To-do Item.png b/ks_dashboard_ninja/static/description/img/To-do Item.png new file mode 100644 index 000000000..a306829c2 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/To-do Item.png differ diff --git a/ks_dashboard_ninja/static/description/img/To_DO.png b/ks_dashboard_ninja/static/description/img/To_DO.png new file mode 100644 index 000000000..ca36cc36c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/To_DO.png differ diff --git a/ks_dashboard_ninja/static/description/img/UID-img.png b/ks_dashboard_ninja/static/description/img/UID-img.png new file mode 100644 index 000000000..965e43bb0 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/UID-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/View_Dashbaord_Items.gif b/ks_dashboard_ninja/static/description/img/View_Dashbaord_Items.gif new file mode 100644 index 000000000..15582e1bb Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/View_Dashbaord_Items.gif differ diff --git a/ks_dashboard_ninja/static/description/img/View_Dashboard _tem_Data.gif b/ks_dashboard_ninja/static/description/img/View_Dashboard _tem_Data.gif new file mode 100644 index 000000000..a4c2f2a76 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/View_Dashboard _tem_Data.gif differ diff --git a/ks_dashboard_ninja/static/description/img/acc_bg.png b/ks_dashboard_ninja/static/description/img/acc_bg.png new file mode 100644 index 000000000..aafcbdb2b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/acc_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/acc_control.png b/ks_dashboard_ninja/static/description/img/acc_control.png new file mode 100644 index 000000000..b97be8ce8 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/acc_control.png differ diff --git a/ks_dashboard_ninja/static/description/img/access-control-img.png b/ks_dashboard_ninja/static/description/img/access-control-img.png new file mode 100644 index 000000000..f0f9d1cbb Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/access-control-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/account.png b/ks_dashboard_ninja/static/description/img/account.png new file mode 100644 index 000000000..b11dabc57 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/account.png differ diff --git a/ks_dashboard_ninja/static/description/img/account2.jpg b/ks_dashboard_ninja/static/description/img/account2.jpg new file mode 100644 index 000000000..7fdc97014 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/account2.jpg differ diff --git a/ks_dashboard_ninja/static/description/img/account3.jpg b/ks_dashboard_ninja/static/description/img/account3.jpg new file mode 100644 index 000000000..1026ca67f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/account3.jpg differ diff --git a/ks_dashboard_ninja/static/description/img/account4.jpg b/ks_dashboard_ninja/static/description/img/account4.jpg new file mode 100644 index 000000000..7d2ff9485 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/account4.jpg differ diff --git a/ks_dashboard_ninja/static/description/img/account5.jpg b/ks_dashboard_ninja/static/description/img/account5.jpg new file mode 100644 index 000000000..6ae5d5e75 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/account5.jpg differ diff --git a/ks_dashboard_ninja/static/description/img/adv-filter-img.png b/ks_dashboard_ninja/static/description/img/adv-filter-img.png new file mode 100644 index 000000000..fe453bb7c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/adv-filter-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/adv.png b/ks_dashboard_ninja/static/description/img/adv.png new file mode 100644 index 000000000..3ae3e8b43 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/adv.png differ diff --git a/ks_dashboard_ninja/static/description/img/adv_filter.png b/ks_dashboard_ninja/static/description/img/adv_filter.png new file mode 100644 index 000000000..010e4dfcc Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/adv_filter.png differ diff --git a/ks_dashboard_ninja/static/description/img/advance.png b/ks_dashboard_ninja/static/description/img/advance.png new file mode 100644 index 000000000..7d8897166 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/advance.png differ diff --git a/ks_dashboard_ninja/static/description/img/af_bg.png b/ks_dashboard_ninja/static/description/img/af_bg.png new file mode 100644 index 000000000..ef9f4ad42 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/af_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/all-featurs.png b/ks_dashboard_ninja/static/description/img/all-featurs.png new file mode 100644 index 000000000..cd65d0e91 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/all-featurs.png differ diff --git a/ks_dashboard_ninja/static/description/img/arrow.png b/ks_dashboard_ninja/static/description/img/arrow.png new file mode 100644 index 000000000..64b41a663 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/arrow.png differ diff --git a/ks_dashboard_ninja/static/description/img/auth.png b/ks_dashboard_ninja/static/description/img/auth.png new file mode 100644 index 000000000..3c173bc83 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/auth.png differ diff --git a/ks_dashboard_ninja/static/description/img/authentic-imgg.png b/ks_dashboard_ninja/static/description/img/authentic-imgg.png new file mode 100644 index 000000000..eda244d17 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/authentic-imgg.png differ diff --git a/ks_dashboard_ninja/static/description/img/barchart.png b/ks_dashboard_ninja/static/description/img/barchart.png new file mode 100644 index 000000000..f0ad744b5 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/barchart.png differ diff --git a/ks_dashboard_ninja/static/description/img/bg_blue.png b/ks_dashboard_ninja/static/description/img/bg_blue.png new file mode 100644 index 000000000..c73aa0fa4 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/bg_blue.png differ diff --git a/ks_dashboard_ninja/static/description/img/cdt.png b/ks_dashboard_ninja/static/description/img/cdt.png new file mode 100644 index 000000000..aaba8e84f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/cdt.png differ diff --git a/ks_dashboard_ninja/static/description/img/cdt_bg.png b/ks_dashboard_ninja/static/description/img/cdt_bg.png new file mode 100644 index 000000000..876b23dd0 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/cdt_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/chart-large-img.png b/ks_dashboard_ninja/static/description/img/chart-large-img.png new file mode 100644 index 000000000..ec8d335cb Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/chart-large-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/com-odoo-img.png b/ks_dashboard_ninja/static/description/img/com-odoo-img.png new file mode 100644 index 000000000..c81be373f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/com-odoo-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/config-img1.png b/ks_dashboard_ninja/static/description/img/config-img1.png new file mode 100644 index 000000000..88a1f1e80 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/config-img1.png differ diff --git a/ks_dashboard_ninja/static/description/img/config-img2.png b/ks_dashboard_ninja/static/description/img/config-img2.png new file mode 100644 index 000000000..e6ce134f3 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/config-img2.png differ diff --git a/ks_dashboard_ninja/static/description/img/contact-place.png b/ks_dashboard_ninja/static/description/img/contact-place.png new file mode 100644 index 000000000..19686fa93 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/contact-place.png differ diff --git a/ks_dashboard_ninja/static/description/img/d_ite_bg.png b/ks_dashboard_ninja/static/description/img/d_ite_bg.png new file mode 100644 index 000000000..4593be50d Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/d_ite_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/dash.png b/ks_dashboard_ninja/static/description/img/dash.png new file mode 100644 index 000000000..68b6c6990 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dash.png differ diff --git a/ks_dashboard_ninja/static/description/img/dash_item.png b/ks_dashboard_ninja/static/description/img/dash_item.png new file mode 100644 index 000000000..be7bd76db Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dash_item.png differ diff --git a/ks_dashboard_ninja/static/description/img/dashboard.png b/ks_dashboard_ninja/static/description/img/dashboard.png new file mode 100644 index 000000000..b7df81588 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dashboard.png differ diff --git a/ks_dashboard_ninja/static/description/img/des_own.png b/ks_dashboard_ninja/static/description/img/des_own.png new file mode 100644 index 000000000..b57183c77 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/des_own.png differ diff --git a/ks_dashboard_ninja/static/description/img/design_mul.png b/ks_dashboard_ninja/static/description/img/design_mul.png new file mode 100644 index 000000000..f465b9ce1 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/design_mul.png differ diff --git a/ks_dashboard_ninja/static/description/img/df.png b/ks_dashboard_ninja/static/description/img/df.png new file mode 100644 index 000000000..fcecaec5e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/df.png differ diff --git a/ks_dashboard_ninja/static/description/img/df2.png b/ks_dashboard_ninja/static/description/img/df2.png new file mode 100644 index 000000000..5384ab029 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/df2.png differ diff --git a/ks_dashboard_ninja/static/description/img/dfbg.png b/ks_dashboard_ninja/static/description/img/dfbg.png new file mode 100644 index 000000000..34e328a92 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dfbg.png differ diff --git a/ks_dashboard_ninja/static/description/img/dmd.png b/ks_dashboard_ninja/static/description/img/dmd.png new file mode 100644 index 000000000..5f2190c8f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dmd.png differ diff --git a/ks_dashboard_ninja/static/description/img/dmd_img.png b/ks_dashboard_ninja/static/description/img/dmd_img.png new file mode 100644 index 000000000..b57183c77 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dmd_img.png differ diff --git a/ks_dashboard_ninja/static/description/img/doug.png b/ks_dashboard_ninja/static/description/img/doug.png new file mode 100644 index 000000000..215999eea Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/doug.png differ diff --git a/ks_dashboard_ninja/static/description/img/download_dash.png b/ks_dashboard_ninja/static/description/img/download_dash.png new file mode 100644 index 000000000..e56026447 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/download_dash.png differ diff --git a/ks_dashboard_ninja/static/description/img/dpc1.png b/ks_dashboard_ninja/static/description/img/dpc1.png new file mode 100644 index 000000000..8a43179b8 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dpc1.png differ diff --git a/ks_dashboard_ninja/static/description/img/dpc2.png b/ks_dashboard_ninja/static/description/img/dpc2.png new file mode 100644 index 000000000..eb82efd21 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dpc2.png differ diff --git a/ks_dashboard_ninja/static/description/img/drill1.png b/ks_dashboard_ninja/static/description/img/drill1.png new file mode 100644 index 000000000..2c0139792 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/drill1.png differ diff --git a/ks_dashboard_ninja/static/description/img/drill2.png b/ks_dashboard_ninja/static/description/img/drill2.png new file mode 100644 index 000000000..36170929f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/drill2.png differ diff --git a/ks_dashboard_ninja/static/description/img/dyn_bg.png b/ks_dashboard_ninja/static/description/img/dyn_bg.png new file mode 100644 index 000000000..419a7b0e3 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/dyn_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/export.png b/ks_dashboard_ninja/static/description/img/export.png new file mode 100644 index 000000000..50df09199 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/export.png differ diff --git a/ks_dashboard_ninja/static/description/img/fet1.png b/ks_dashboard_ninja/static/description/img/fet1.png new file mode 100644 index 000000000..5e8b74700 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/fet1.png differ diff --git a/ks_dashboard_ninja/static/description/img/fullbg.png b/ks_dashboard_ninja/static/description/img/fullbg.png new file mode 100644 index 000000000..0439d5573 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/fullbg.png differ diff --git a/ks_dashboard_ninja/static/description/img/horizental.png b/ks_dashboard_ninja/static/description/img/horizental.png new file mode 100644 index 000000000..3a9b35c95 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/horizental.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon1.png b/ks_dashboard_ninja/static/description/img/icon1.png new file mode 100644 index 000000000..6845156e3 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon1.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon10.png b/ks_dashboard_ninja/static/description/img/icon10.png new file mode 100644 index 000000000..9affd2ba7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon10.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon2.png b/ks_dashboard_ninja/static/description/img/icon2.png new file mode 100644 index 000000000..603f72004 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon2.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon20.png b/ks_dashboard_ninja/static/description/img/icon20.png new file mode 100644 index 000000000..94c2c6099 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon20.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon21.png b/ks_dashboard_ninja/static/description/img/icon21.png new file mode 100644 index 000000000..d0e1aae4a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon21.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon22.png b/ks_dashboard_ninja/static/description/img/icon22.png new file mode 100644 index 000000000..573c2bfbe Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon22.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon23.png b/ks_dashboard_ninja/static/description/img/icon23.png new file mode 100644 index 000000000..4544fd9f2 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon23.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon24.png b/ks_dashboard_ninja/static/description/img/icon24.png new file mode 100644 index 000000000..fac286680 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon24.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon25.png b/ks_dashboard_ninja/static/description/img/icon25.png new file mode 100644 index 000000000..77823d7f9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon25.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon26.png b/ks_dashboard_ninja/static/description/img/icon26.png new file mode 100644 index 000000000..d6c0cb06e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon26.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon27.png b/ks_dashboard_ninja/static/description/img/icon27.png new file mode 100644 index 000000000..688af45d2 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon27.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon28.png b/ks_dashboard_ninja/static/description/img/icon28.png new file mode 100644 index 000000000..c74c2fda5 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon28.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon29.png b/ks_dashboard_ninja/static/description/img/icon29.png new file mode 100644 index 000000000..dfebd34c7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon29.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon3.png b/ks_dashboard_ninja/static/description/img/icon3.png new file mode 100644 index 000000000..7216d2978 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon3.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon30.png b/ks_dashboard_ninja/static/description/img/icon30.png new file mode 100644 index 000000000..3e328a176 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon30.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon4.png b/ks_dashboard_ninja/static/description/img/icon4.png new file mode 100644 index 000000000..230e45209 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon4.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon5.png b/ks_dashboard_ninja/static/description/img/icon5.png new file mode 100644 index 000000000..5889ba46b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon5.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon6.png b/ks_dashboard_ninja/static/description/img/icon6.png new file mode 100644 index 000000000..cae8e54c1 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon6.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon7.png b/ks_dashboard_ninja/static/description/img/icon7.png new file mode 100644 index 000000000..be8b3af3c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon7.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon8.png b/ks_dashboard_ninja/static/description/img/icon8.png new file mode 100644 index 000000000..be68db405 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon8.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon9.png b/ks_dashboard_ninja/static/description/img/icon9.png new file mode 100644 index 000000000..84a8ce51f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon9.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_1.png b/ks_dashboard_ninja/static/description/img/icon_1.png new file mode 100644 index 000000000..8c4ab0dc7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_1.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_10.png b/ks_dashboard_ninja/static/description/img/icon_10.png new file mode 100644 index 000000000..4e0b506c6 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_10.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_11.png b/ks_dashboard_ninja/static/description/img/icon_11.png new file mode 100644 index 000000000..cf796cac8 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_11.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_12.png b/ks_dashboard_ninja/static/description/img/icon_12.png new file mode 100644 index 000000000..96dfaeea6 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_12.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_13.png b/ks_dashboard_ninja/static/description/img/icon_13.png new file mode 100644 index 000000000..d656e78cd Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_13.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_14.png b/ks_dashboard_ninja/static/description/img/icon_14.png new file mode 100644 index 000000000..dfc12412f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_14.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_15.png b/ks_dashboard_ninja/static/description/img/icon_15.png new file mode 100644 index 000000000..f131d540f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_15.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_16.png b/ks_dashboard_ninja/static/description/img/icon_16.png new file mode 100644 index 000000000..19ff3afe4 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_16.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_17.png b/ks_dashboard_ninja/static/description/img/icon_17.png new file mode 100644 index 000000000..a7a9a16df Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_17.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_18.png b/ks_dashboard_ninja/static/description/img/icon_18.png new file mode 100644 index 000000000..0e5eec1c5 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_18.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_19.png b/ks_dashboard_ninja/static/description/img/icon_19.png new file mode 100644 index 000000000..be360ca63 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_19.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_2.png b/ks_dashboard_ninja/static/description/img/icon_2.png new file mode 100644 index 000000000..22667bde7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_2.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_20.png b/ks_dashboard_ninja/static/description/img/icon_20.png new file mode 100644 index 000000000..94c2c6099 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_20.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_3.png b/ks_dashboard_ninja/static/description/img/icon_3.png new file mode 100644 index 000000000..14a748ff2 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_3.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_4.png b/ks_dashboard_ninja/static/description/img/icon_4.png new file mode 100644 index 000000000..7e4920b5c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_4.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_5.png b/ks_dashboard_ninja/static/description/img/icon_5.png new file mode 100644 index 000000000..eaeda3087 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_5.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_6.png b/ks_dashboard_ninja/static/description/img/icon_6.png new file mode 100644 index 000000000..d806d6acd Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_6.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_7.png b/ks_dashboard_ninja/static/description/img/icon_7.png new file mode 100644 index 000000000..0c9b7fc52 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_7.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_8.png b/ks_dashboard_ninja/static/description/img/icon_8.png new file mode 100644 index 000000000..a7d3c115a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_8.png differ diff --git a/ks_dashboard_ninja/static/description/img/icon_9.png b/ks_dashboard_ninja/static/description/img/icon_9.png new file mode 100644 index 000000000..3b5269821 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/icon_9.png differ diff --git a/ks_dashboard_ninja/static/description/img/ksolves_awards_logo.png b/ks_dashboard_ninja/static/description/img/ksolves_awards_logo.png new file mode 100644 index 000000000..bb41451a0 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/ksolves_awards_logo.png differ diff --git a/ks_dashboard_ninja/static/description/img/left.png b/ks_dashboard_ninja/static/description/img/left.png new file mode 100644 index 000000000..03c1566f9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/left.png differ diff --git a/ks_dashboard_ninja/static/description/img/line_Chart.png b/ks_dashboard_ninja/static/description/img/line_Chart.png new file mode 100644 index 000000000..e3207200b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/line_Chart.png differ diff --git a/ks_dashboard_ninja/static/description/img/list_view1.png b/ks_dashboard_ninja/static/description/img/list_view1.png new file mode 100644 index 000000000..23b205a4f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/list_view1.png differ diff --git a/ks_dashboard_ninja/static/description/img/list_view2.png b/ks_dashboard_ninja/static/description/img/list_view2.png new file mode 100644 index 000000000..ea2bc7e4e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/list_view2.png differ diff --git a/ks_dashboard_ninja/static/description/img/logo.png b/ks_dashboard_ninja/static/description/img/logo.png new file mode 100644 index 000000000..fa7830db9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/logo.png differ diff --git a/ks_dashboard_ninja/static/description/img/m.png b/ks_dashboard_ninja/static/description/img/m.png new file mode 100644 index 000000000..b87b0859e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/m.png differ diff --git a/ks_dashboard_ninja/static/description/img/mail.png b/ks_dashboard_ninja/static/description/img/mail.png new file mode 100644 index 000000000..b87b0859e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/mail.png differ diff --git a/ks_dashboard_ninja/static/description/img/multi (2).png b/ks_dashboard_ninja/static/description/img/multi (2).png new file mode 100644 index 000000000..34fd47f51 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/multi (2).png differ diff --git a/ks_dashboard_ninja/static/description/img/multi.png b/ks_dashboard_ninja/static/description/img/multi.png new file mode 100644 index 000000000..a0760ef8e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/multi.png differ diff --git a/ks_dashboard_ninja/static/description/img/multi_img.png b/ks_dashboard_ninja/static/description/img/multi_img.png new file mode 100644 index 000000000..92c55d1af Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/multi_img.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/bg-top-new.png b/ks_dashboard_ninja/static/description/img/new-add-img/bg-top-new.png new file mode 100644 index 000000000..288e19028 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/bg-top-new.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/dashboard-video.gif b/ks_dashboard_ninja/static/description/img/new-add-img/dashboard-video.gif new file mode 100644 index 000000000..c568ff9e7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/dashboard-video.gif differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e1.png b/ks_dashboard_ninja/static/description/img/new-add-img/e1.png new file mode 100644 index 000000000..0350ad73f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e1.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e2.png b/ks_dashboard_ninja/static/description/img/new-add-img/e2.png new file mode 100644 index 000000000..bf0535e16 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e2.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e3.png b/ks_dashboard_ninja/static/description/img/new-add-img/e3.png new file mode 100644 index 000000000..bfdf8453b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e3.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e4.png b/ks_dashboard_ninja/static/description/img/new-add-img/e4.png new file mode 100644 index 000000000..0fec7dfef Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e4.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e5.png b/ks_dashboard_ninja/static/description/img/new-add-img/e5.png new file mode 100644 index 000000000..319734bb5 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e5.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e6.png b/ks_dashboard_ninja/static/description/img/new-add-img/e6.png new file mode 100644 index 000000000..8fa87ae5b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e6.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e7.png b/ks_dashboard_ninja/static/description/img/new-add-img/e7.png new file mode 100644 index 000000000..637df2409 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e7.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e8.png b/ks_dashboard_ninja/static/description/img/new-add-img/e8.png new file mode 100644 index 000000000..1b3aa41dc Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e8.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/e9.png b/ks_dashboard_ninja/static/description/img/new-add-img/e9.png new file mode 100644 index 000000000..e73ba1917 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/e9.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/excel-bg.png b/ks_dashboard_ninja/static/description/img/new-add-img/excel-bg.png new file mode 100644 index 000000000..912112871 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/excel-bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/excel-img.png b/ks_dashboard_ninja/static/description/img/new-add-img/excel-img.png new file mode 100644 index 000000000..aac07e97e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/excel-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/i1.png b/ks_dashboard_ninja/static/description/img/new-add-img/i1.png new file mode 100644 index 000000000..3ff1487e4 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/i1.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/i2.png b/ks_dashboard_ninja/static/description/img/new-add-img/i2.png new file mode 100644 index 000000000..518e69349 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/i2.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/i3.png b/ks_dashboard_ninja/static/description/img/new-add-img/i3.png new file mode 100644 index 000000000..ff2da96ca Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/i3.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/i4.png b/ks_dashboard_ninja/static/description/img/new-add-img/i4.png new file mode 100644 index 000000000..8517e9c36 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/i4.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/i5.png b/ks_dashboard_ninja/static/description/img/new-add-img/i5.png new file mode 100644 index 000000000..7d3f67697 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/i5.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/i6.png b/ks_dashboard_ninja/static/description/img/new-add-img/i6.png new file mode 100644 index 000000000..aa5fefff4 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/i6.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/i7.png b/ks_dashboard_ninja/static/description/img/new-add-img/i7.png new file mode 100644 index 000000000..97853e409 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/i7.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/icon-link.png b/ks_dashboard_ninja/static/description/img/new-add-img/icon-link.png new file mode 100644 index 000000000..84c052f3c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/icon-link.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/n1.png b/ks_dashboard_ninja/static/description/img/new-add-img/n1.png new file mode 100644 index 000000000..a6aac48b9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/n1.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/n2.png b/ks_dashboard_ninja/static/description/img/new-add-img/n2.png new file mode 100644 index 000000000..993ee209d Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/n2.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/n3.png b/ks_dashboard_ninja/static/description/img/new-add-img/n3.png new file mode 100644 index 000000000..fb95e9fe1 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/n3.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/n4.png b/ks_dashboard_ninja/static/description/img/new-add-img/n4.png new file mode 100644 index 000000000..cf97c7838 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/n4.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/n5.png b/ks_dashboard_ninja/static/description/img/new-add-img/n5.png new file mode 100644 index 000000000..09a13a8fc Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/n5.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/n6.png b/ks_dashboard_ninja/static/description/img/new-add-img/n6.png new file mode 100644 index 000000000..7c011b7a7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/n6.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-add-img/n7.png b/ks_dashboard_ninja/static/description/img/new-add-img/n7.png new file mode 100644 index 000000000..55f3c30b7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-add-img/n7.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/default_4.gif b/ks_dashboard_ninja/static/description/img/new-dscr-img/default_4.gif new file mode 100644 index 000000000..cda440d8a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/default_4.gif differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/down-arrow.svg b/ks_dashboard_ninja/static/description/img/new-dscr-img/down-arrow.svg new file mode 100644 index 000000000..3a6d9a84c --- /dev/null +++ b/ks_dashboard_ninja/static/description/img/new-dscr-img/down-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/email.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/email.png new file mode 100644 index 000000000..4179c0168 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/email.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/full-shadow.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/full-shadow.png new file mode 100644 index 000000000..23b744ec6 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/full-shadow.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_1.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_1.png new file mode 100644 index 000000000..3f9a4ec21 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_1.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_10.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_10.png new file mode 100644 index 000000000..4068df2b9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_10.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_11.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_11.png new file mode 100644 index 000000000..8cd9cce94 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_11.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_12.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_12.png new file mode 100644 index 000000000..d74688760 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_12.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_2.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_2.png new file mode 100644 index 000000000..cbff1a038 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_2.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_3.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_3.png new file mode 100644 index 000000000..837d48348 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_3.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_4.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_4.png new file mode 100644 index 000000000..2770ef5d0 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_4.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_5.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_5.png new file mode 100644 index 000000000..111adbd5e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_5.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_6.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_6.png new file mode 100644 index 000000000..dbb56827c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_6.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_7.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_7.png new file mode 100644 index 000000000..42a2657ed Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_7.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_8.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_8.png new file mode 100644 index 000000000..8c213d62f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_8.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_9.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_9.png new file mode 100644 index 000000000..aa5b6fe51 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_9.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_1.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_1.png new file mode 100644 index 000000000..b30397b7a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_1.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_10.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_10.png new file mode 100644 index 000000000..cbb6452e3 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_10.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_11.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_11.png new file mode 100644 index 000000000..daac6c753 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_11.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_2.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_2.png new file mode 100644 index 000000000..9f79c2e83 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_2.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_3.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_3.png new file mode 100644 index 000000000..69a170dd4 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_3.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_4.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_4.png new file mode 100644 index 000000000..1cda15bcb Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_4.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_5.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_5.png new file mode 100644 index 000000000..a4bfb3d68 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_5.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_6.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_6.png new file mode 100644 index 000000000..f4876e77d Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_6.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_7.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_7.png new file mode 100644 index 000000000..46571e317 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_7.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_8.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_8.png new file mode 100644 index 000000000..048af930f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_8.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_9.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_9.png new file mode 100644 index 000000000..9cf7ef4ac Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_c_9.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_map_img.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_map_img.png new file mode 100644 index 000000000..79d4e3201 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/ks_map_img.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/phone-view.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/phone-view.png new file mode 100644 index 000000000..6722a98dc Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/phone-view.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/product.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/product.png new file mode 100644 index 000000000..8915de08c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/product.png differ diff --git a/ks_dashboard_ninja/static/description/img/new-dscr-img/solution.png b/ks_dashboard_ninja/static/description/img/new-dscr-img/solution.png new file mode 100644 index 000000000..241f3991a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/new-dscr-img/solution.png differ diff --git a/ks_dashboard_ninja/static/description/img/odoo.png b/ks_dashboard_ninja/static/description/img/odoo.png new file mode 100644 index 000000000..c51ed0c7e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/odoo.png differ diff --git a/ks_dashboard_ninja/static/description/img/odoo_com.png b/ks_dashboard_ninja/static/description/img/odoo_com.png new file mode 100644 index 000000000..1c637702a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/odoo_com.png differ diff --git a/ks_dashboard_ninja/static/description/img/odoo_dash.png b/ks_dashboard_ninja/static/description/img/odoo_dash.png new file mode 100644 index 000000000..2b1c96900 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/odoo_dash.png differ diff --git a/ks_dashboard_ninja/static/description/img/odoo_dash_img.png b/ks_dashboard_ninja/static/description/img/odoo_dash_img.png new file mode 100644 index 000000000..ea80195e5 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/odoo_dash_img.png differ diff --git a/ks_dashboard_ninja/static/description/img/odoo_dash_img_rtl.png b/ks_dashboard_ninja/static/description/img/odoo_dash_img_rtl.png new file mode 100644 index 000000000..be4f6ecb9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/odoo_dash_img_rtl.png differ diff --git a/ks_dashboard_ninja/static/description/img/odoo_ent.png b/ks_dashboard_ninja/static/description/img/odoo_ent.png new file mode 100644 index 000000000..4e3af6b5f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/odoo_ent.png differ diff --git a/ks_dashboard_ninja/static/description/img/p.png b/ks_dashboard_ninja/static/description/img/p.png new file mode 100644 index 000000000..fd1e8e88c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/p.png differ diff --git a/ks_dashboard_ninja/static/description/img/ph.png b/ks_dashboard_ninja/static/description/img/ph.png new file mode 100644 index 000000000..2215b503a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/ph.png differ diff --git a/ks_dashboard_ninja/static/description/img/phone.png b/ks_dashboard_ninja/static/description/img/phone.png new file mode 100644 index 000000000..2215b503a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/phone.png differ diff --git a/ks_dashboard_ninja/static/description/img/pie_chart.png b/ks_dashboard_ninja/static/description/img/pie_chart.png new file mode 100644 index 000000000..3d7cb5c72 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/pie_chart.png differ diff --git a/ks_dashboard_ninja/static/description/img/play-btn-rtl.png b/ks_dashboard_ninja/static/description/img/play-btn-rtl.png new file mode 100644 index 000000000..ec24db014 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/play-btn-rtl.png differ diff --git a/ks_dashboard_ninja/static/description/img/play-icon.png b/ks_dashboard_ninja/static/description/img/play-icon.png new file mode 100644 index 000000000..a3d92de45 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/play-icon.png differ diff --git a/ks_dashboard_ninja/static/description/img/polar_area_chart.png b/ks_dashboard_ninja/static/description/img/polar_area_chart.png new file mode 100644 index 000000000..73be472c1 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/polar_area_chart.png differ diff --git a/ks_dashboard_ninja/static/description/img/pre.png b/ks_dashboard_ninja/static/description/img/pre.png new file mode 100644 index 000000000..0a45d487d Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/pre.png differ diff --git a/ks_dashboard_ninja/static/description/img/real_time.png b/ks_dashboard_ninja/static/description/img/real_time.png new file mode 100644 index 000000000..98f60ca18 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/real_time.png differ diff --git a/ks_dashboard_ninja/static/description/img/rel_bg.png b/ks_dashboard_ninja/static/description/img/rel_bg.png new file mode 100644 index 000000000..70f5dcd7d Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/rel_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/reporting_bg.png b/ks_dashboard_ninja/static/description/img/reporting_bg.png new file mode 100644 index 000000000..f74981380 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/reporting_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/resp.png b/ks_dashboard_ninja/static/description/img/resp.png new file mode 100644 index 000000000..54d3ca793 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/resp.png differ diff --git a/ks_dashboard_ninja/static/description/img/responive_fluid.png b/ks_dashboard_ninja/static/description/img/responive_fluid.png new file mode 100644 index 000000000..6ce9e3c5f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/responive_fluid.png differ diff --git a/ks_dashboard_ninja/static/description/img/right.png b/ks_dashboard_ninja/static/description/img/right.png new file mode 100644 index 000000000..eb091667f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/right.png differ diff --git a/ks_dashboard_ninja/static/description/img/rtl_img.png b/ks_dashboard_ninja/static/description/img/rtl_img.png new file mode 100644 index 000000000..c6f4a49de Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/rtl_img.png differ diff --git a/ks_dashboard_ninja/static/description/img/s.png b/ks_dashboard_ninja/static/description/img/s.png new file mode 100644 index 000000000..f7d0de2f6 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/s.png differ diff --git a/ks_dashboard_ninja/static/description/img/selected.svg b/ks_dashboard_ninja/static/description/img/selected.svg new file mode 100644 index 000000000..9992817e0 --- /dev/null +++ b/ks_dashboard_ninja/static/description/img/selected.svg @@ -0,0 +1,4 @@ + + + + diff --git a/ks_dashboard_ninja/static/description/img/set-target-img.png b/ks_dashboard_ninja/static/description/img/set-target-img.png new file mode 100644 index 000000000..116aa5088 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/set-target-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/set_bg.png b/ks_dashboard_ninja/static/description/img/set_bg.png new file mode 100644 index 000000000..9a249aa7a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/set_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/set_target.png b/ks_dashboard_ninja/static/description/img/set_target.png new file mode 100644 index 000000000..72c3dbdc0 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/set_target.png differ diff --git a/ks_dashboard_ninja/static/description/img/set_target1.png b/ks_dashboard_ninja/static/description/img/set_target1.png new file mode 100644 index 000000000..683df3ea8 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/set_target1.png differ diff --git a/ks_dashboard_ninja/static/description/img/setbg.png b/ks_dashboard_ninja/static/description/img/setbg.png new file mode 100644 index 000000000..9a249aa7a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/setbg.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/Dashboard-Ninja-Advance.png b/ks_dashboard_ninja/static/description/img/support/Dashboard-Ninja-Advance.png new file mode 100644 index 000000000..c8502494b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/Dashboard-Ninja-Advance.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/Dashboard-Ninja.png b/ks_dashboard_ninja/static/description/img/support/Dashboard-Ninja.png new file mode 100644 index 000000000..19b70ec9d Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/Dashboard-Ninja.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/Odoo-WooCommerce.png b/ks_dashboard_ninja/static/description/img/support/Odoo-WooCommerce.png new file mode 100644 index 000000000..90f92a34c Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/Odoo-WooCommerce.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/arc-backend-theme.png b/ks_dashboard_ninja/static/description/img/support/arc-backend-theme.png new file mode 100644 index 000000000..bac2a2f0e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/arc-backend-theme.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/db-nina.png b/ks_dashboard_ninja/static/description/img/support/db-nina.png new file mode 100644 index 000000000..9fbddce11 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/db-nina.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/dfr.png b/ks_dashboard_ninja/static/description/img/support/dfr.png new file mode 100644 index 000000000..ff23f8f18 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/dfr.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/ks-odoo-services-bg.png b/ks_dashboard_ninja/static/description/img/support/ks-odoo-services-bg.png new file mode 100644 index 000000000..b62ff5c75 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/ks-odoo-services-bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/list-view-manager.png b/ks_dashboard_ninja/static/description/img/support/list-view-manager.png new file mode 100644 index 000000000..dcdcd1a29 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/list-view-manager.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/odoo-arc.png b/ks_dashboard_ninja/static/description/img/support/odoo-arc.png new file mode 100644 index 000000000..a9f8e576f Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/odoo-arc.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/odoo-base.png b/ks_dashboard_ninja/static/description/img/support/odoo-base.png new file mode 100644 index 000000000..aae055017 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/odoo-base.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/odoo-gantt.png b/ks_dashboard_ninja/static/description/img/support/odoo-gantt.png new file mode 100644 index 000000000..7c54ad4b6 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/odoo-gantt.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/odoo-kernal.png b/ks_dashboard_ninja/static/description/img/support/odoo-kernal.png new file mode 100644 index 000000000..e737f0d3b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/odoo-kernal.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/odoo-lb-ninja.png b/ks_dashboard_ninja/static/description/img/support/odoo-lb-ninja.png new file mode 100644 index 000000000..6c8e3c613 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/odoo-lb-ninja.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/odoo-woo.png b/ks_dashboard_ninja/static/description/img/support/odoo-woo.png new file mode 100644 index 000000000..d950b7911 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/odoo-woo.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/report.png b/ks_dashboard_ninja/static/description/img/support/report.png new file mode 100644 index 000000000..82a58bcf3 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/report.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/services-img.png b/ks_dashboard_ninja/static/description/img/support/services-img.png new file mode 100644 index 000000000..07c1328c8 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/services-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/shopify.png b/ks_dashboard_ninja/static/description/img/support/shopify.png new file mode 100644 index 000000000..223dd0cee Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/shopify.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/support-bg.png b/ks_dashboard_ninja/static/description/img/support/support-bg.png new file mode 100644 index 000000000..0adaf7d2b Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/support-bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/support.png b/ks_dashboard_ninja/static/description/img/support/support.png new file mode 100644 index 000000000..24e47ebdf Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/support.png differ diff --git a/ks_dashboard_ninja/static/description/img/support/theme-kinetik.png b/ks_dashboard_ninja/static/description/img/support/theme-kinetik.png new file mode 100644 index 000000000..ca6ebc5b7 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/support/theme-kinetik.png differ diff --git a/ks_dashboard_ninja/static/description/img/t1.png b/ks_dashboard_ninja/static/description/img/t1.png new file mode 100644 index 000000000..299cc29b8 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/t1.png differ diff --git a/ks_dashboard_ninja/static/description/img/t2.png b/ks_dashboard_ninja/static/description/img/t2.png new file mode 100644 index 000000000..6db1ee80e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/t2.png differ diff --git a/ks_dashboard_ninja/static/description/img/t3.png b/ks_dashboard_ninja/static/description/img/t3.png new file mode 100644 index 000000000..35cb3cbde Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/t3.png differ diff --git a/ks_dashboard_ninja/static/description/img/t4.png b/ks_dashboard_ninja/static/description/img/t4.png new file mode 100644 index 000000000..24cd0c016 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/t4.png differ diff --git a/ks_dashboard_ninja/static/description/img/t5.png b/ks_dashboard_ninja/static/description/img/t5.png new file mode 100644 index 000000000..1e44de87a Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/t5.png differ diff --git a/ks_dashboard_ninja/static/description/img/t6.png b/ks_dashboard_ninja/static/description/img/t6.png new file mode 100644 index 000000000..e9c671311 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/t6.png differ diff --git a/ks_dashboard_ninja/static/description/img/tiles.png b/ks_dashboard_ninja/static/description/img/tiles.png new file mode 100644 index 000000000..64102b1cf Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/tiles.png differ diff --git a/ks_dashboard_ninja/static/description/img/to-do-img.png b/ks_dashboard_ninja/static/description/img/to-do-img.png new file mode 100644 index 000000000..18cb11bdc Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/to-do-img.png differ diff --git a/ks_dashboard_ninja/static/description/img/todo_bg.png b/ks_dashboard_ninja/static/description/img/todo_bg.png new file mode 100644 index 000000000..d02ee85eb Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/todo_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/todo_item.png b/ks_dashboard_ninja/static/description/img/todo_item.png new file mode 100644 index 000000000..35a8459ba Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/todo_item.png differ diff --git a/ks_dashboard_ninja/static/description/img/top-logo/logo1.png b/ks_dashboard_ninja/static/description/img/top-logo/logo1.png new file mode 100644 index 000000000..fea92a268 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/top-logo/logo1.png differ diff --git a/ks_dashboard_ninja/static/description/img/top-logo/logo2.png b/ks_dashboard_ninja/static/description/img/top-logo/logo2.png new file mode 100644 index 000000000..d91d39eac Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/top-logo/logo2.png differ diff --git a/ks_dashboard_ninja/static/description/img/top-logo/logo3.png b/ks_dashboard_ninja/static/description/img/top-logo/logo3.png new file mode 100644 index 000000000..861ad9bbf Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/top-logo/logo3.png differ diff --git a/ks_dashboard_ninja/static/description/img/unique.png b/ks_dashboard_ninja/static/description/img/unique.png new file mode 100644 index 000000000..496713028 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/unique.png differ diff --git a/ks_dashboard_ninja/static/description/img/unique_bg.png b/ks_dashboard_ninja/static/description/img/unique_bg.png new file mode 100644 index 000000000..561ba9862 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/unique_bg.png differ diff --git a/ks_dashboard_ninja/static/description/img/user_guide.png b/ks_dashboard_ninja/static/description/img/user_guide.png new file mode 100644 index 000000000..932e2f946 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/user_guide.png differ diff --git a/ks_dashboard_ninja/static/description/img/view_dash.png b/ks_dashboard_ninja/static/description/img/view_dash.png new file mode 100644 index 000000000..c872c01e9 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/view_dash.png differ diff --git a/ks_dashboard_ninja/static/description/img/wave.svg b/ks_dashboard_ninja/static/description/img/wave.svg new file mode 100644 index 000000000..2f445f352 --- /dev/null +++ b/ks_dashboard_ninja/static/description/img/wave.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ks_dashboard_ninja/static/description/img/why-ksolves/ks_curved_backend_theme.png b/ks_dashboard_ninja/static/description/img/why-ksolves/ks_curved_backend_theme.png new file mode 100644 index 000000000..bac2a2f0e Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/why-ksolves/ks_curved_backend_theme.png differ diff --git a/ks_dashboard_ninja/static/description/img/why-ksolves/ks_dashboard_ninja.png b/ks_dashboard_ninja/static/description/img/why-ksolves/ks_dashboard_ninja.png new file mode 100644 index 000000000..c626ef338 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/why-ksolves/ks_dashboard_ninja.png differ diff --git a/ks_dashboard_ninja/static/description/img/why-ksolves/ks_gantt_view_base.png b/ks_dashboard_ninja/static/description/img/why-ksolves/ks_gantt_view_base.png new file mode 100644 index 000000000..aae055017 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/why-ksolves/ks_gantt_view_base.png differ diff --git a/ks_dashboard_ninja/static/description/img/why-ksolves/perfect_combo.png b/ks_dashboard_ninja/static/description/img/why-ksolves/perfect_combo.png new file mode 100644 index 000000000..ce53f52e1 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/why-ksolves/perfect_combo.png differ diff --git a/ks_dashboard_ninja/static/description/img/youtube-link.png b/ks_dashboard_ninja/static/description/img/youtube-link.png new file mode 100644 index 000000000..96cd3fd36 Binary files /dev/null and b/ks_dashboard_ninja/static/description/img/youtube-link.png differ diff --git a/ks_dashboard_ninja/static/description/index.html b/ks_dashboard_ninja/static/description/index.html new file mode 100644 index 000000000..94661f0e8 --- /dev/null +++ b/ks_dashboard_ninja/static/description/index.html @@ -0,0 +1,4399 @@ + + + + + Odoo Dashboard Ninja | Descrition + + + + + + + + + + + +
+
+
+
+
+ ks-logo +
+
+
+ logo +
+
+ odoo-logo +
+
+
+ + +
+
+
+
+ Ksolves - Your one-stop solution +
+

+ We are available 24/7 for your service. Contact us today! +

+
+
+
+
+
+

+ WATCH DEMO

+
+
+
+
+
+
+
+
+ + + + video-img +
+
+
+
+
+
+
+
+
+ User Guide +
+
User + Guide +
+
+
+
+ Copy
Link +
+
+ https://www.ksolves.com/user-guide/odoo-dashboard-ninja +
+
+
+
+
+
+
+  contact-man-icon +
+ +
+
+
+
+
+ + +
+ +
+
+

+ Dashboard Ninja with AI + Dashboard Ninja with AI +

+
+
+

+ Create amazing reports with the powerful & smart Odoo Dashboard Ninja app for Odoo. See your + business from a 360-degree angle with an interactive, engaging, and beautiful dashboard. +

+
+
+
+
+
+ +
+
+ + + + + + +
+
+

+ What makes
+ Odoo Dashboard Ninja + Unique +

+
+
+

+ The ultimate time and money saving Odoo tool for your Business. +

+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+

+ Dynamic & Animated +
+ Reporting Dashboards +

+
+
+

+ Supports 17 impressive Odoo dashboard item types for easy business data + interpretation. + (Tiles, + Line Chart, List View, Bar Chart, Horizontal Bar Chart, Area Chart, To-do + Item, + Polar + Area + Chart, Pie Chart, Doughnut Charts, Flower Chart, Funnel Chart, Radial Chart, Radar Chart, + Scatter Chart, Bullet Chart & Map view) +

+
+ +
+
+
+
+ acc_bg +
+
+
+

+ Generate Items with AI +

+
+
+

+ Generate multiple items for your Odoo Dashboard with AI. Gain the flexibility to choose from a range of charts and graphs and save them with ease. +

+
+
+
+ gif +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Generate keyword-focused Odoo Dashboard Items with AI +

+
+
+

+ Now just provide the keyword, and AI will create the dashboard items for you within seconds. +

+
+
+
+ gif +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Generate Complete Odoo Dashboard with AI +

+
+
+

+ Save your time and effort! Generate a complete Odoo Dashboard for a specific model within a few clicks with AI efficiency. +

+
+
+
+ gif +
+
+
+
+ gif +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Extract Chart Insights With AI + +

+
+
+

+ Interpret complex charts with single-click AI-generated explanations! Identify hidden patterns & trends and make informed data-backed business decisions. +

+
+
+
+ gif +
+
+
+
+
+
+ +
+
+
+
+

+ Real-Time + Streaming + Dashboard +

+

+ Upgrades the data in real-time to + give a 360 view of the business performance. This feature will update the + data + if + any changes occur from the backend in real-time or after a specific interval + of + time. +

+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+

+ Responsive
+ Fluid & Flexible
+ Layout
+

+

+ Conveniently view your data over different devices such as Mobile, Desktop, + or + Tablet for easy access. + It offers an optimized browsing experience to track business performance on + the + go. +

+
+
+
+
+
+
+ advance +
+
+
+
+

+ Advanced
+ Date Filter + +

+

+ Present data in a timely manner over a selected period in the date filter + option. + Select from 20 predefined date filters (Last 7 days, Last 30 days, Last 90 + days, + & + more) or choose a custom date. +

+
+
+
+
+ +
+
+
+
+
+
+ advance +
+
+
+
+ +
+
+
+
+

+ Create Charts
+ From
+ + EXCEL AND CSV FILES + +

+

+ Easily upload Excel or CSV files, and let the system automatically synchronize the data. It will then process the data and create charts. +

+
+
+ +
+
+
+
+
+
+

+ Download Odoo Dashboard Items + +
+ (Excel, CSV, PDF, PNG) +

+
+
+

+ Exported data items can be used for offline presentations, seminars, or emails. +

+
+
+ +
+
+
+
+
+
+

+ Export & Import Dashboards + + +
+ or Specific Odoo Dashboard Items + +

+
+
+

+ Export an entire Odoo Dashboard or Specific Odoo Dashboard Item to a same system + or different Odoo instances for saving time and effort while migrating from one + system + to another. +

+
+
+
+ +
+
+
+
+
+ advance +
+
+
+
+

+ Access
+ Control + +

+

+ Control who can access the Odoo dashboard with a single click + for robust security. +

+
+
+
+
+ access-control-img +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Paid + Predefined + Dashboards +

+
+
+

+ 5 Predefined Odoo dashboards are provided for different verticals of + a company(Sales, CRM, Account, Inventory, & POS). Customize them as per your + need. +

+
+
+
+ +
+
+
+
+
+ +
+ acc_bg +
+
+
+
+

+ Drill Down / +
Drill Up Data +

+

+ Modify the degree of details presented in a dashboard entity. Drill-down to + access detailed data or drill-up to get a broader view of information. +

+
+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+
+ +
+
+
+
+

+ Community/
Enterprise/
Odoo.sh Support +

+

+ Odoo Dashboard Ninja supports the Community, Enterprise, and Odoo.Sh Edition of + Odoo + v10, + v11, v12, v13, v14, v15, v16 & v17. +

+
+
+
+
+
+
+ acc_bg +
+
+
+
+

+ Duplicate/Move +
+ Dashboard +

+

+ If you have mistakenly created a Odoo dashboard item in another Dashboard, don't + worry, you can duplicate/move it to your required Odoo dashboard easily with the + Duplicate/Move option. +

+
+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+ +
+
+
+

+ Customizable +
+ Dashboard Tile +

+

+ Customize Odoo dashboard items with predefined font style, font icons or + upload + icons, + font color, background color, and 6 predefined layouts. +

+
+
+
+
+
+
+ acc_bg +
+
+
+
+

+ Data Filtration - +
+ Group By, Limit & Sort By +

+

+ Group By, Sort By, Limit, filter condition to get desired data for any + dashboard + item as per your requirement. +

+
+
+
+ +
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Dashboard Item + + 2 List View Styles +

+
+
+

+ Use the list-view item to view multi-value data sets in a grouped or ungrouped + manner. + Example: To see the total sales, average sales, total quotations of the top 10 + sales + persons. +

+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Design Multiple + + Dashboards +

+
+
+

+ Over a single platform, one can create as many dashboards as required to + support a large number of business/department requirements. +

+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Dashboard + + + Personalization/Configuration +

+
+
+

+ Configure the dashboard name, menu, group access, choose the sequence, + and more while creating interactive presentable dashboards for your business. +

+
+ +
+
+ +
+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Design + + Your Own Dashboard Layout +

+
+
+

+ Design your dashboard layouts by resizing, dragging, repositioning the dashboard + items, + and renaming the dashboard heading for arranging all items as per your need. +

+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ View Dashboard + + Item Data +

+
+
+

+ Users can hover over any dashboard chart and get quick access to the data from + the + dashboard window. + By clicking on the Info Icon, the user can get every detail associated with a + particular + chart. +

+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Multi - + Color + Themes +

+
+
+

+ Beautiful, interactive, and outstanding multi-colored themes can be added to + your + dashboard. +

+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+
+ set-target-img +
+
+
+
+

+ Set +
+ Targets + + +

+

+ Target feature helps to present clear and concise performance information + without + providing complex formulas or knowledge. +
+
+ Receive instant email notifications when your sales targets are met. + Effortlessly track your KPIs, ensure your team stays motivated and aligned with your objectives. + + +

+
+
+
+
+
+
+ acc_bg +
+
+
+
+

+ Unique User ID + (%UID) +

+

+ Filter logged-in user data using %UID in domain filter to see the results + related to + the logged-in user. +

+
+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+
+ +
+
+
+
+

+ Authentic + %MYCOMPANY Filter +

+

+ Get company-oriented details by filtering the logged-in user data using this + dynamic filter. +

+
+
+
+
+
+
+ acc_bg +
+
+
+
+

+ To do + item +

+

+ A user can keep track of his/her activities with a to-do list. To-do items + can + be + used as a useful reminder of specific tasks. +

+
+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Instant + + Edit Mode +

+
+
+

+ A user can edit the basic information of any dashboard items + instantly with Quick Edit Mode without going to the detailed edit screen. +

+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+

+ Number + + Systems +

+
+
+

+ Track the data in your country format with the pre-defined Number system
+ options (English Format, Indian Format, Colombian Peso Format, and Exact Value) +

+
+
+
+ +
+
+
+
+
+
+ acc_bg +
+
+
+
+ +
+
+
+
+

+ Show/Hide
+ Data Values +

+

+ Show/hide value on Dashboard Items to read the statistics easily for making + impressive + business decisions. +

+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ acc_bg +
+
+
+
+

+ RTL + Support +

+

+ Odoo Dashboard Ninja gives you the freedom to work in Right-to-Left + language-oriented + interface for increasing productivity. +

+
+
+
+
+
+
+ + + + video-img +
+
+
+
+
+
+
+
+
+
+
+ Why + Ksolves +
+

+ You know us as the + makers of the Odoo "Dashboard Ninja", + You +
+ will remember us with Odoo WooCommerce Connecter +

+
    +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
+
+ +
+
+ Client + Success +
+

+ Invest + your trust like our elite clientele did! +

+
    +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
  • + logo-img +
  • +
+
+ +
+

+ Products That Blends Together +

+

+ Related Products You May Be Interested In! +

+
+
+ + + + + + + + + + + +
+ + logo +
+ Odoo Dashboard Ninja +
+
+
+ + + + + logo +
+ Arc Backend Theme +
+
+
+ + + + + logo +
+ Odoo Gantt View Base +
+
+
+ = + +
+ logo +
+ Perfect Combo +
+
+
+
+
+
+
+
+
+

+ Ksolves is 24/7 open to discuss your thoughts and queries! +

+ + + +
+
+ +
+
+ +
+
+
+
+
+ + +
+

+ You have to add your valid email id in General Settings under "AI API Key" Section and click on "Get API Key". You will receive the Key over mail once your credentials are verified. +

+
+ + +
+

+ We never send the data to AI; neither AI needs data to generate the charts. We only send the table structure to the Ksolves AI Server. Hence, we ensure data security of the customers.For AI insights feature we simply send the summarized and unlabeled data to our AI server for processing. Since the data is unlabeled, our AI server does not store it. Consequently, neither we nor our AI server can determine the company to which the data pertains. +

+
+ + +
+

+ Yes, you can use all AI features after purchasing the module. +

+
+ + +
+

+ Yes, our app works with Odoo Enterprise as well as Community. +

+
+ + +
+

+ Please drop email at sales@ksolves.com or raise a ticket through Odoo store + itself. +

+
+ + +
+
+

+ When you create a dashboard, an action is created with name : Menu Name + + "Action". So for example if you create a dashboard with name : Project + Dashboard. Go to any user page -> Preference -> Home Action and can select + action with name : Project Dashboard Action. +

+
+
+ + +
+
+

+ Yes, we do provide free support for 90 days for any queries or any bug/issue + fixing. +

+
+
+ + + +
+
+

+ Yes, we have provided a feature to move and duplicate any item from one + dashboard to another. When you mouseover any item you will see a copy icon + or + click on edit icon and from top center of screen there is Actions dropdown + with + options to move/duplicate items. +

+
+
+ + + +
+
+

+ Pretty simple, just click on Gear like icon present at top right of screen + and + then click on edit layout option. Now, when you mouseover any tile or chart + you + will see resize icon at bottom right of item using which you can resize + items as + per your need. +

+
+
+ + + + +
+
+

+ No, it is not typical behavior for Odoo Dashboard Ninja to automatically change the + layout of + dashboards unless there are underlying customizations to the code, record rules, + group access, + or custom addons/themes on your server that may be conflicting with Dashboard + Ninja. +

+

+ If you are experiencing unexpected changes to your dashboard layouts, we + recommend reaching out to our + team at odoo.helpdesk@ksolves.in. We can help you debug the issue on your server + and provide a suitable + solution to address the problem. +

+
+
+
+
+
+
+
+
+
+

+ Latest Release + 2.2.3 +

+ + 14th August, + 2024 + +
+
+
+
+
+ Fixes +
+
+
    +
  • Fix - Custom filter search bar UI issue. +
  • Fix - Automatically opening the data while exporting the item (KPI and Tile). +
+
+
+
+
+
+
+
+

+ Release + 2.2.2 +

+ + 9th August, + 2024 + +
+
+
+
+
+ Improvements +
+
+
    +
  • Storing date filter and custom filters in cache to prevent them from disappearing after reloading. +
  • Fix - When selecting the model in item it is not showing all models. +
+
+
+
+
+
+
+
+

+ Release + 2.2.1 +

+ + 6th August, + 2024 + +
+
+
+
+
+ Fixes +
+
+
    +
  • Fix -Showing error while importing dashboard or item. +
+
+
+
+
+
+
+
+

+ Release + 2.2.0 +

+ + 22nd July, + 2024 + +
+
+
+
+
+ New Feature +
+
+
    +
  • Enable users to set the target. +
+
+
+
+
+
+
+
+

+ Release + 2.1.4 +

+ + 19th July, + 2024 + +
+
+
+
+
+ Fixes +
+
+
    +
  • Fix - Code conflict with List View Manager module(showing border in odoo default list view header). +
+
+
+
+
+
+
+
+

+ Release + 2.1.3 +

+ + 12th July, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Fix - Barchart and line chart UI issue when using negative multiplier value. +
+
+
+
+
+
+
+
+

+ Release + 2.1.2 +

+ + 4th July, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Fixed dashboard multi layout selection not clickable issue. +
  • +
  • Fixed List item code conflict with List View Manager module. +
  • +
+
+
+
+
+
+ +
+
+

+ Release + 2.1.1 +

+ + 2nd July, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Fixed the KPI item data calculation issues. +
  • +
  • Fixed the tooltip UI issue in charts when user uses RTL language. +
  • +
  • Improved the working of Custom Filter for non-admin users. +
  • +
  • Fixed the amount calculation issue in tile when selecting the number system as the exact amount. +
  • +
  • Fixed the fill temporal value issue when using datetime field in group by. +
  • +
+
+
+
+
+
+ +
+
+

+ Release + 2.1.0 +

+ + 13th June, + 2024 + +
+
+
+
+
+ New Feature +
+
+
    +
  • Enable users to use %UID and %MYCOMPANY in Domain. +
  • +
  • Enable List view in Drill Down. +
  • +
+
+
+
+
+
+
+
+

+ Release + 2.0.1 +

+ + 11th June, + 2024 + +
+
+
+
+
+ Enhancement +
+
+
    +
  • Code Enhancement for Excel and CSV. +
  • +
+
+
+
+
+
+
+
+

+ Release + 2.0.0 +

+ + 3rd June, + 2024 + +
+
+
+
+
+ New Feature +
+
+
    +
  • Show/Hide Data values of charts. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.9.0 +

+ + 22nd May, + 2024 + +
+
+
+
+
+ New Feature +
+
+
    +
  • Extract Chart Insights With AI. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.8.4 +

+ + 21st May, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Fixed charts generation using AI. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.8.3 +

+ + 6th May, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Fixed Warning logs. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.8.2 +

+ + 29th April, + 2024 + +
+
+
+
+
+ Improvement +
+
+
    +
  • Improved custom icon functionality for Tile item.. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.8.1 +

+ + 25th April, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Issue fixed: sort by field while creating the Bar Chart.. +
  • +
  • Document module issue fixed. +
  • +
  • Field Data reading issue fixed. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.8.0 +

+ + 22nd April, + 2024 + +
+
+
+
+
+ New Feature +
+
+
    +
  • Company Wise Items. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.7.6 +

+ + 19th April, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Fixed Date custom filter issue. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.7.5 +

+ + 16th April, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Date conversion issue fixed in any other languages. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.7.4 +

+ + 12th April, + 2024 + +
+
+
+
+
+ Bug Fixed +
+
+
    +
  • Date conversion issue fixed. +
  • +
  • Legends position issue fixed. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.7.3 +

+ + 20th March, + 2024 + +
+
+
+
+
+ Improvement +
+
+
    +
  • Functionality of the i button for charts. +
  • +
  • Manage legends position in Arabic for charts. +
  • +
  • Manage group by values in Arabic for charts. +
  • +
  • Dark Theme issue fixed. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.7.2 +

+ + 1st March, + 2024 + +
+
+
+
+
+ Enhancement +
+
+
    +
  • Implemented rotated labels in Horizontal Bar Chart,Bar Chart,Line Chart,Area Chart and Bullet chart. +
  • +
  • Manage legends position in Flower Chart,Radial Chart,Radar Chart and Polar Chart. +
  • +
  • Manage legend based on group by in Pie and Doughnut Chart. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.7.1 +

+ + 26th February, + 2024 + +
+
+ +
+
+
+ Fixes +
+
+
    +
  • Fixed KPI sales target issue. +
  • +
  • Fixed KPI progress bar view issue. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.7.0 +

+ + 15th February, + 2024 + +
+
+ +
+
+
+ New Feature +
+
+
    +
  • Added custom filters on Dashboard. +
  • +
+
+
+ Fixes +
+
    +
  • Fixed multi-dashboard layout bugs. +
  • +
+
+
+
+
+
+
+

+ Release + 1.6.1 +

+ + 12th February, + 2024 + +
+
+ +
+
+
+ Fixes +
+
+
    +
  • Fixed the log issues. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.6.0 +

+ + 5th February, + 2024 + +
+
+ +
+
+
+ New Feature +
+
+
    +
  • Added New UI theme for Dashboard. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.5.2 +

+ + 30th January, + 2024 + +
+
+ +
+
+
+ Enhancement +
+
+
    +
  • UI changes for Demo user. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.5.1 +

+ + 29th January, + 2024 + +
+
+ +
+
+
+ Enhancement +
+
+
    +
  • Added Props for AI Dashboard.. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.5.0 +

+ + 24th January, + 2024 + +
+
+ +
+
+
+ New Features +
+
+
    +
  • Added Pre-defined Filter on Dashboard.. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.4.0 +

+ + 19th January, + 2024 + +
+
+ +
+
+
+ New Features +
+
+
    +
  • Added Date Filter on Dashboard.. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.3.1 +

+ + 17th January, + 2024 + +
+
+ +
+
+
+ Improvement +
+
+
    +
  • Deprecated method removed. +
  • + + +
+
+
+
+
+
+
+
+

+ Release + 1.3.0 +

+ + 7th December, + 2023 + +
+
+ +
+
+
+ New Features +
+
+
    +
  • Added Excel and CSV functionality for the charts.. +
  • +
  • Added Drill Down functionality for charts. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.2.0 +

+ + 1st December, + 2023 + +
+
+ +
+
+
+ New Features +
+
+
    +
  • Real time streaming. +
  • +
  • Delete, Move and update item without reloading. +
  • + +
+
+
+
+
+
+
+
+

+ Release + 1.1.0 +

+ + 30th November, + 2023 + +
+
+ +
+
+
+ New Features +
+
+
    +
  • Generate Dashboard items with AI. +
  • +
  • Generate Complete Dashboard with AI. +
  • +
  • Generate Dashboard items using keywords with AI. +
  • +
+
+
+
+
+
+
+
+

+ Release + 1.0.0 +

+ + 27th November, + 2023 + +
+
+ +
+
+
+ New version +
+
+
    +
  • Latest version 17 release of Dashboard Ninja . +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+

+ All + Features +

+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Generate Complete
+ Dashboard With AI +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Generate Items
+ With AI +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Generate Keyword-Focused
+ Dashboard Items With AI +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Extract Chart Insights
+ With AI +

+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+

+ Dynamic & Animated Reporting Dashboards +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Real-Time
+ Streaming Dashboard +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Responsive: Fluid
+ & Flexible Layout +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Advanced
+ Date Filter +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Download Dashboard Items + (Excel, CSV, PDF, PNG) +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Export & Import Dashboards + or Specific Dashboard Items +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Access
+ Control +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Predefined
+ Dashboards +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Drill Down/
+ Drill Up Data +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Community/Enterprise/
+ Odoo.sh Support +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Duplicate/
+ Move Dashboard +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Customizable
+ Dashboard Tile Items +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Data Filtration -
+ Group By, Limit & Sort By +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Dashboard Item -
+ 2 List View Styles +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Design Multiple
+ Dashboards +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Dashboard Personalization
+ /Configuration +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Personalized & Interactive + Dashboard Layouts +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ View Dashboard
+ Item Data +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Multi-Color
+ Themes +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Set Targets +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Unique User
+ ID (%UID) +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Authentic
+ %MYCOMPANY Filter +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ To do item +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Instant
+ Edit Mode +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Number
+ Systems +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Show/Hide
+ Data Values +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Monetary/
+ Custom Units +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Multi-Company
Support +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Multi-Language
Support +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

+ Multi-Currency
Support +

+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ bg-img +
+
+ +
+
+
+ Free 90 Days + Support +
+

+ Ksolves will provide FREE 90 days support for any doubt, queries, and bug fixing + (excluding data recovery) or any type of issues related to this module. This is + applicable from the date of purchase.

+
+
+
+
+
+
+

+ Note + Extensively Tested on Odoo Vanilla with Ubuntu OS

+
+
+
+ + + +
+
+
+ bg-img +
+
+
+ Ksolves Odoo Services +
+ +
+
+ +
+
+
+
+
+
+ + + + + + diff --git a/ks_dashboard_ninja/static/description/js/bootstrap.bundle.min.js b/ks_dashboard_ninja/static/description/js/bootstrap.bundle.min.js new file mode 100644 index 000000000..3af2dc364 --- /dev/null +++ b/ks_dashboard_ninja/static/description/js/bootstrap.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery")):"function"==typeof define&&define.amd?define(["exports","jquery"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery)}(this,(function(t,e){"use strict";function n(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var i=n(e);function o(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};u.jQueryDetection(),i.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return i.default(this).one(u.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||u.triggerTransitionEnd(e)}),t),this},i.default.event.special[u.TRANSITION_END]={bindType:l,delegateType:l,handle:function(t){if(i.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var f="bs.alert",d=i.default.fn.alert,c=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){i.default.removeData(this._element,f),this._element=null},e._getRootElement=function(t){var e=u.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=i.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=i.default.Event("close.bs.alert");return i.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(i.default(t).removeClass("show"),i.default(t).hasClass("fade")){var n=u.getTransitionDurationFromElement(t);i.default(t).one(u.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){i.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data(f);o||(o=new t(this),n.data(f,o)),"close"===e&&o[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},r(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();i.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',c._handleDismiss(new c)),i.default.fn.alert=c._jQueryInterface,i.default.fn.alert.Constructor=c,i.default.fn.alert.noConflict=function(){return i.default.fn.alert=d,c._jQueryInterface};var h="bs.button",p=i.default.fn.button,m="active",g='[data-toggle^="button"]',_='input:not([type="hidden"])',v=".btn",b=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=i.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var o=this._element.querySelector(_);if(o){if("radio"===o.type)if(o.checked&&this._element.classList.contains(m))t=!1;else{var r=n.querySelector(".active");r&&i.default(r).removeClass(m)}t&&("checkbox"!==o.type&&"radio"!==o.type||(o.checked=!this._element.classList.contains(m)),this.shouldAvoidTriggerChange||i.default(o).trigger("change")),o.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(m)),t&&i.default(this._element).toggleClass(m))},e.dispose=function(){i.default.removeData(this._element,h),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var o=i.default(this),r=o.data(h);r||(r=new t(this),o.data(h,r)),r.shouldAvoidTriggerChange=n,"toggle"===e&&r[e]()}))},r(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();i.default(document).on("click.bs.button.data-api",g,(function(t){var e=t.target,n=e;if(i.default(e).hasClass("btn")||(e=i.default(e).closest(v)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var o=e.querySelector(_);if(o&&(o.hasAttribute("disabled")||o.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||b._jQueryInterface.call(i.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",g,(function(t){var e=i.default(t.target).closest(v)[0];i.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),i.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(C)},e.nextWhenVisible=function(){var t=i.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(S)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(u.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(D);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)i.default(this._element).one(N,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var o=t>n?C:S;this._slide(o,this._items[t])}},e.dispose=function(){i.default(this._element).off(".bs.carousel"),i.default.removeData(this._element,E),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=a({},A,t),u.typeCheckConfig(y,t,k),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&i.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&i.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&I[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&I[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};i.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(i.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),i.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(i.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),i.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),i.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===C,i=t===S,o=this._getItemIndex(e),r=this._items.length-1;if((i&&0===o||n&&o===r)&&!this._config.wrap)return e;var a=(o+(t===S?-1:1))%this._items.length;return-1===a?this._items[this._items.length-1]:this._items[a]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),o=this._getItemIndex(this._element.querySelector(D)),r=i.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:o,to:n});return i.default(this._element).trigger(r),r},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));i.default(e).removeClass(T);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&i.default(n).addClass(T)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(D);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,o,r,a=this,s=this._element.querySelector(D),l=this._getItemIndex(s),f=e||s&&this._getItemByDirection(t,s),d=this._getItemIndex(f),c=Boolean(this._interval);if(t===C?(n="carousel-item-left",o="carousel-item-next",r="left"):(n="carousel-item-right",o="carousel-item-prev",r="right"),f&&i.default(f).hasClass(T))this._isSliding=!1;else if(!this._triggerSlideEvent(f,r).isDefaultPrevented()&&s&&f){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(f),this._activeElement=f;var h=i.default.Event(N,{relatedTarget:f,direction:r,from:l,to:d});if(i.default(this._element).hasClass("slide")){i.default(f).addClass(o),u.reflow(f),i.default(s).addClass(n),i.default(f).addClass(n);var p=u.getTransitionDurationFromElement(s);i.default(s).one(u.TRANSITION_END,(function(){i.default(f).removeClass(n+" "+o).addClass(T),i.default(s).removeClass("active "+o+" "+n),a._isSliding=!1,setTimeout((function(){return i.default(a._element).trigger(h)}),0)})).emulateTransitionEnd(p)}else i.default(s).removeClass(T),i.default(f).addClass(T),this._isSliding=!1,i.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this).data(E),o=a({},A,i.default(this).data());"object"==typeof e&&(o=a({},o,e));var r="string"==typeof e?e:o.slide;if(n||(n=new t(this,o),i.default(this).data(E,n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if("undefined"==typeof n[r])throw new TypeError('No method named "'+r+'"');n[r]()}else o.interval&&o.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=u.getSelectorFromElement(this);if(n){var o=i.default(n)[0];if(o&&i.default(o).hasClass("carousel")){var r=a({},i.default(o).data(),i.default(this).data()),s=this.getAttribute("data-slide-to");s&&(r.interval=!1),t._jQueryInterface.call(i.default(o),r),s&&i.default(o).data(E).to(s),e.preventDefault()}}},r(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return A}}]),t}();i.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",O._dataApiClickHandler),i.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=a,this._triggerArray.push(r))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){i.default(this._element).hasClass(P)?this.hide():this.show()},e.show=function(){var e,n,o=this;if(!(this._isTransitioning||i.default(this._element).hasClass(P)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof o._config.parent?t.getAttribute("data-parent")===o._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=i.default(e).not(this._selector).data(j))&&n._isTransitioning))){var r=i.default.Event("show.bs.collapse");if(i.default(this._element).trigger(r),!r.isDefaultPrevented()){e&&(t._jQueryInterface.call(i.default(e).not(this._selector),"hide"),n||i.default(e).data(j,null));var a=this._getDimension();i.default(this._element).removeClass(F).addClass(R),this._element.style[a]=0,this._triggerArray.length&&i.default(this._triggerArray).removeClass(H).attr("aria-expanded",!0),this.setTransitioning(!0);var s="scroll"+(a[0].toUpperCase()+a.slice(1)),l=u.getTransitionDurationFromElement(this._element);i.default(this._element).one(u.TRANSITION_END,(function(){i.default(o._element).removeClass(R).addClass("collapse show"),o._element.style[a]="",o.setTransitioning(!1),i.default(o._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(l),this._element.style[a]=this._element[s]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&i.default(this._element).hasClass(P)){var e=i.default.Event("hide.bs.collapse");if(i.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",u.reflow(this._element),i.default(this._element).addClass(R).removeClass("collapse show");var o=this._triggerArray.length;if(o>0)for(var r=0;r=0)return 1;return 0}(),Y=U&&window.Promise?function(t){var e=!1;return function(){e||(e=!0,window.Promise.resolve().then((function(){e=!1,t()})))}}:function(t){var e=!1;return function(){e||(e=!0,setTimeout((function(){e=!1,t()}),V))}};function z(t){return t&&"[object Function]"==={}.toString.call(t)}function K(t,e){if(1!==t.nodeType)return[];var n=t.ownerDocument.defaultView.getComputedStyle(t,null);return e?n[e]:n}function X(t){return"HTML"===t.nodeName?t:t.parentNode||t.host}function G(t){if(!t)return document.body;switch(t.nodeName){case"HTML":case"BODY":return t.ownerDocument.body;case"#document":return t.body}var e=K(t),n=e.overflow,i=e.overflowX,o=e.overflowY;return/(auto|scroll|overlay)/.test(n+o+i)?t:G(X(t))}function $(t){return t&&t.referenceNode?t.referenceNode:t}var J=U&&!(!window.MSInputMethodContext||!document.documentMode),Z=U&&/MSIE 10/.test(navigator.userAgent);function tt(t){return 11===t?J:10===t?Z:J||Z}function et(t){if(!t)return document.documentElement;for(var e=tt(10)?document.body:null,n=t.offsetParent||null;n===e&&t.nextElementSibling;)n=(t=t.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&"BODY"!==i&&"HTML"!==i?-1!==["TH","TD","TABLE"].indexOf(n.nodeName)&&"static"===K(n,"position")?et(n):n:t?t.ownerDocument.documentElement:document.documentElement}function nt(t){return null!==t.parentNode?nt(t.parentNode):t}function it(t,e){if(!(t&&t.nodeType&&e&&e.nodeType))return document.documentElement;var n=t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING,i=n?t:e,o=n?e:t,r=document.createRange();r.setStart(i,0),r.setEnd(o,0);var a,s,l=r.commonAncestorContainer;if(t!==l&&e!==l||i.contains(o))return"BODY"===(s=(a=l).nodeName)||"HTML"!==s&&et(a.firstElementChild)!==a?et(l):l;var u=nt(t);return u.host?it(u.host,e):it(t,nt(e).host)}function ot(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"top",n="top"===e?"scrollTop":"scrollLeft",i=t.nodeName;if("BODY"===i||"HTML"===i){var o=t.ownerDocument.documentElement,r=t.ownerDocument.scrollingElement||o;return r[n]}return t[n]}function rt(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=ot(e,"top"),o=ot(e,"left"),r=n?-1:1;return t.top+=i*r,t.bottom+=i*r,t.left+=o*r,t.right+=o*r,t}function at(t,e){var n="x"===e?"Left":"Top",i="Left"===n?"Right":"Bottom";return parseFloat(t["border"+n+"Width"])+parseFloat(t["border"+i+"Width"])}function st(t,e,n,i){return Math.max(e["offset"+t],e["scroll"+t],n["client"+t],n["offset"+t],n["scroll"+t],tt(10)?parseInt(n["offset"+t])+parseInt(i["margin"+("Height"===t?"Top":"Left")])+parseInt(i["margin"+("Height"===t?"Bottom":"Right")]):0)}function lt(t){var e=t.body,n=t.documentElement,i=tt(10)&&getComputedStyle(n);return{height:st("Height",e,n,i),width:st("Width",e,n,i)}}var ut=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},ft=function(){function t(t,e){for(var n=0;n2&&void 0!==arguments[2]&&arguments[2],i=tt(10),o="HTML"===e.nodeName,r=pt(t),a=pt(e),s=G(t),l=K(e),u=parseFloat(l.borderTopWidth),f=parseFloat(l.borderLeftWidth);n&&o&&(a.top=Math.max(a.top,0),a.left=Math.max(a.left,0));var d=ht({top:r.top-a.top-u,left:r.left-a.left-f,width:r.width,height:r.height});if(d.marginTop=0,d.marginLeft=0,!i&&o){var c=parseFloat(l.marginTop),h=parseFloat(l.marginLeft);d.top-=u-c,d.bottom-=u-c,d.left-=f-h,d.right-=f-h,d.marginTop=c,d.marginLeft=h}return(i&&!n?e.contains(s):e===s&&"BODY"!==s.nodeName)&&(d=rt(d,e)),d}function gt(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=t.ownerDocument.documentElement,i=mt(t,n),o=Math.max(n.clientWidth,window.innerWidth||0),r=Math.max(n.clientHeight,window.innerHeight||0),a=e?0:ot(n),s=e?0:ot(n,"left"),l={top:a-i.top+i.marginTop,left:s-i.left+i.marginLeft,width:o,height:r};return ht(l)}function _t(t){var e=t.nodeName;if("BODY"===e||"HTML"===e)return!1;if("fixed"===K(t,"position"))return!0;var n=X(t);return!!n&&_t(n)}function vt(t){if(!t||!t.parentElement||tt())return document.documentElement;for(var e=t.parentElement;e&&"none"===K(e,"transform");)e=e.parentElement;return e||document.documentElement}function bt(t,e,n,i){var o=arguments.length>4&&void 0!==arguments[4]&&arguments[4],r={top:0,left:0},a=o?vt(t):it(t,$(e));if("viewport"===i)r=gt(a,o);else{var s=void 0;"scrollParent"===i?"BODY"===(s=G(X(e))).nodeName&&(s=t.ownerDocument.documentElement):s="window"===i?t.ownerDocument.documentElement:i;var l=mt(s,a,o);if("HTML"!==s.nodeName||_t(a))r=l;else{var u=lt(t.ownerDocument),f=u.height,d=u.width;r.top+=l.top-l.marginTop,r.bottom=f+l.top,r.left+=l.left-l.marginLeft,r.right=d+l.left}}var c="number"==typeof(n=n||0);return r.left+=c?n:n.left||0,r.top+=c?n:n.top||0,r.right-=c?n:n.right||0,r.bottom-=c?n:n.bottom||0,r}function yt(t){return t.width*t.height}function Et(t,e,n,i,o){var r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;if(-1===t.indexOf("auto"))return t;var a=bt(n,i,r,o),s={top:{width:a.width,height:e.top-a.top},right:{width:a.right-e.right,height:a.height},bottom:{width:a.width,height:a.bottom-e.bottom},left:{width:e.left-a.left,height:a.height}},l=Object.keys(s).map((function(t){return ct({key:t},s[t],{area:yt(s[t])})})).sort((function(t,e){return e.area-t.area})),u=l.filter((function(t){var e=t.width,i=t.height;return e>=n.clientWidth&&i>=n.clientHeight})),f=u.length>0?u[0].key:l[0].key,d=t.split("-")[1];return f+(d?"-"+d:"")}function wt(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,o=i?vt(e):it(e,$(n));return mt(n,o,i)}function Tt(t){var e=t.ownerDocument.defaultView.getComputedStyle(t),n=parseFloat(e.marginTop||0)+parseFloat(e.marginBottom||0),i=parseFloat(e.marginLeft||0)+parseFloat(e.marginRight||0);return{width:t.offsetWidth+i,height:t.offsetHeight+n}}function Ct(t){var e={left:"right",right:"left",bottom:"top",top:"bottom"};return t.replace(/left|right|bottom|top/g,(function(t){return e[t]}))}function St(t,e,n){n=n.split("-")[0];var i=Tt(t),o={width:i.width,height:i.height},r=-1!==["right","left"].indexOf(n),a=r?"top":"left",s=r?"left":"top",l=r?"height":"width",u=r?"width":"height";return o[a]=e[a]+e[l]/2-i[l]/2,o[s]=n===s?e[s]-i[u]:e[Ct(s)],o}function Nt(t,e){return Array.prototype.find?t.find(e):t.filter(e)[0]}function Dt(t,e,n){return(void 0===n?t:t.slice(0,function(t,e,n){if(Array.prototype.findIndex)return t.findIndex((function(t){return t.name===n}));var i=Nt(t,(function(t){return t.name===n}));return t.indexOf(i)}(t,0,n))).forEach((function(t){t.function&&console.warn("`modifier.function` is deprecated, use `modifier.fn`!");var n=t.function||t.fn;t.enabled&&z(n)&&(e.offsets.popper=ht(e.offsets.popper),e.offsets.reference=ht(e.offsets.reference),e=n(e,t))})),e}function At(){if(!this.state.isDestroyed){var t={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};t.offsets.reference=wt(this.state,this.popper,this.reference,this.options.positionFixed),t.placement=Et(this.options.placement,t.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),t.originalPlacement=t.placement,t.positionFixed=this.options.positionFixed,t.offsets.popper=St(this.popper,t.offsets.reference,t.placement),t.offsets.popper.position=this.options.positionFixed?"fixed":"absolute",t=Dt(this.modifiers,t),this.state.isCreated?this.options.onUpdate(t):(this.state.isCreated=!0,this.options.onCreate(t))}}function kt(t,e){return t.some((function(t){var n=t.name;return t.enabled&&n===e}))}function It(t){for(var e=[!1,"ms","Webkit","Moz","O"],n=t.charAt(0).toUpperCase()+t.slice(1),i=0;i1&&void 0!==arguments[1]&&arguments[1],n=Qt.indexOf(t),i=Qt.slice(n+1).concat(Qt.slice(0,n));return e?i.reverse():i}var Ut={placement:"bottom",positionFixed:!1,eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:{shift:{order:100,enabled:!0,fn:function(t){var e=t.placement,n=e.split("-")[0],i=e.split("-")[1];if(i){var o=t.offsets,r=o.reference,a=o.popper,s=-1!==["bottom","top"].indexOf(n),l=s?"left":"top",u=s?"width":"height",f={start:dt({},l,r[l]),end:dt({},l,r[l]+r[u]-a[u])};t.offsets.popper=ct({},a,f[i])}return t}},offset:{order:200,enabled:!0,fn:function(t,e){var n,i=e.offset,o=t.placement,r=t.offsets,a=r.popper,s=r.reference,l=o.split("-")[0];return n=Rt(+i)?[+i,0]:function(t,e,n,i){var o=[0,0],r=-1!==["right","left"].indexOf(i),a=t.split(/(\+|\-)/).map((function(t){return t.trim()})),s=a.indexOf(Nt(a,(function(t){return-1!==t.search(/,|\s/)})));a[s]&&-1===a[s].indexOf(",")&&console.warn("Offsets separated by white space(s) are deprecated, use a comma (,) instead.");var l=/\s*,\s*|\s+/,u=-1!==s?[a.slice(0,s).concat([a[s].split(l)[0]]),[a[s].split(l)[1]].concat(a.slice(s+1))]:[a];return u=u.map((function(t,i){var o=(1===i?!r:r)?"height":"width",a=!1;return t.reduce((function(t,e){return""===t[t.length-1]&&-1!==["+","-"].indexOf(e)?(t[t.length-1]=e,a=!0,t):a?(t[t.length-1]+=e,a=!1,t):t.concat(e)}),[]).map((function(t){return function(t,e,n,i){var o=t.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),r=+o[1],a=o[2];return r?0===a.indexOf("%")?ht("%p"===a?n:i)[e]/100*r:"vh"===a||"vw"===a?("vh"===a?Math.max(document.documentElement.clientHeight,window.innerHeight||0):Math.max(document.documentElement.clientWidth,window.innerWidth||0))/100*r:r:t}(t,o,e,n)}))})),u.forEach((function(t,e){t.forEach((function(n,i){Rt(n)&&(o[e]+=n*("-"===t[i-1]?-1:1))}))})),o}(i,a,s,l),"left"===l?(a.top+=n[0],a.left-=n[1]):"right"===l?(a.top+=n[0],a.left+=n[1]):"top"===l?(a.left+=n[0],a.top-=n[1]):"bottom"===l&&(a.left+=n[0],a.top+=n[1]),t.popper=a,t},offset:0},preventOverflow:{order:300,enabled:!0,fn:function(t,e){var n=e.boundariesElement||et(t.instance.popper);t.instance.reference===n&&(n=et(n));var i=It("transform"),o=t.instance.popper.style,r=o.top,a=o.left,s=o[i];o.top="",o.left="",o[i]="";var l=bt(t.instance.popper,t.instance.reference,e.padding,n,t.positionFixed);o.top=r,o.left=a,o[i]=s,e.boundaries=l;var u=e.priority,f=t.offsets.popper,d={primary:function(t){var n=f[t];return f[t]l[t]&&!e.escapeWithReference&&(i=Math.min(f[n],l[t]-("right"===t?f.width:f.height))),dt({},n,i)}};return u.forEach((function(t){var e=-1!==["left","top"].indexOf(t)?"primary":"secondary";f=ct({},f,d[e](t))})),t.offsets.popper=f,t},priority:["left","right","top","bottom"],padding:5,boundariesElement:"scrollParent"},keepTogether:{order:400,enabled:!0,fn:function(t){var e=t.offsets,n=e.popper,i=e.reference,o=t.placement.split("-")[0],r=Math.floor,a=-1!==["top","bottom"].indexOf(o),s=a?"right":"bottom",l=a?"left":"top",u=a?"width":"height";return n[s]r(i[s])&&(t.offsets.popper[l]=r(i[s])),t}},arrow:{order:500,enabled:!0,fn:function(t,e){var n;if(!qt(t.instance.modifiers,"arrow","keepTogether"))return t;var i=e.element;if("string"==typeof i){if(!(i=t.instance.popper.querySelector(i)))return t}else if(!t.instance.popper.contains(i))return console.warn("WARNING: `arrow.element` must be child of its popper element!"),t;var o=t.placement.split("-")[0],r=t.offsets,a=r.popper,s=r.reference,l=-1!==["left","right"].indexOf(o),u=l?"height":"width",f=l?"Top":"Left",d=f.toLowerCase(),c=l?"left":"top",h=l?"bottom":"right",p=Tt(i)[u];s[h]-pa[h]&&(t.offsets.popper[d]+=s[d]+p-a[h]),t.offsets.popper=ht(t.offsets.popper);var m=s[d]+s[u]/2-p/2,g=K(t.instance.popper),_=parseFloat(g["margin"+f]),v=parseFloat(g["border"+f+"Width"]),b=m-t.offsets.popper[d]-_-v;return b=Math.max(Math.min(a[u]-p,b),0),t.arrowElement=i,t.offsets.arrow=(dt(n={},d,Math.round(b)),dt(n,c,""),n),t},element:"[x-arrow]"},flip:{order:600,enabled:!0,fn:function(t,e){if(kt(t.instance.modifiers,"inner"))return t;if(t.flipped&&t.placement===t.originalPlacement)return t;var n=bt(t.instance.popper,t.instance.reference,e.padding,e.boundariesElement,t.positionFixed),i=t.placement.split("-")[0],o=Ct(i),r=t.placement.split("-")[1]||"",a=[];switch(e.behavior){case"flip":a=[i,o];break;case"clockwise":a=Wt(i);break;case"counterclockwise":a=Wt(i,!0);break;default:a=e.behavior}return a.forEach((function(s,l){if(i!==s||a.length===l+1)return t;i=t.placement.split("-")[0],o=Ct(i);var u=t.offsets.popper,f=t.offsets.reference,d=Math.floor,c="left"===i&&d(u.right)>d(f.left)||"right"===i&&d(u.left)d(f.top)||"bottom"===i&&d(u.top)d(n.right),m=d(u.top)d(n.bottom),_="left"===i&&h||"right"===i&&p||"top"===i&&m||"bottom"===i&&g,v=-1!==["top","bottom"].indexOf(i),b=!!e.flipVariations&&(v&&"start"===r&&h||v&&"end"===r&&p||!v&&"start"===r&&m||!v&&"end"===r&&g),y=!!e.flipVariationsByContent&&(v&&"start"===r&&p||v&&"end"===r&&h||!v&&"start"===r&&g||!v&&"end"===r&&m),E=b||y;(c||_||E)&&(t.flipped=!0,(c||_)&&(i=a[l+1]),E&&(r=function(t){return"end"===t?"start":"start"===t?"end":t}(r)),t.placement=i+(r?"-"+r:""),t.offsets.popper=ct({},t.offsets.popper,St(t.instance.popper,t.offsets.reference,t.placement)),t=Dt(t.instance.modifiers,t,"flip"))})),t},behavior:"flip",padding:5,boundariesElement:"viewport",flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(t){var e=t.placement,n=e.split("-")[0],i=t.offsets,o=i.popper,r=i.reference,a=-1!==["left","right"].indexOf(n),s=-1===["top","left"].indexOf(n);return o[a?"left":"top"]=r[n]-(s?o[a?"width":"height"]:0),t.placement=Ct(e),t.offsets.popper=ht(o),t}},hide:{order:800,enabled:!0,fn:function(t){if(!qt(t.instance.modifiers,"hide","preventOverflow"))return t;var e=t.offsets.reference,n=Nt(t.instance.modifiers,(function(t){return"preventOverflow"===t.name})).boundaries;if(e.bottomn.right||e.top>n.bottom||e.right2&&void 0!==arguments[2]?arguments[2]:{};ut(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(i.update)},this.update=Y(this.update.bind(this)),this.options=ct({},t.Defaults,o),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=e&&e.jquery?e[0]:e,this.popper=n&&n.jquery?n[0]:n,this.options.modifiers={},Object.keys(ct({},t.Defaults.modifiers,o.modifiers)).forEach((function(e){i.options.modifiers[e]=ct({},t.Defaults.modifiers[e]||{},o.modifiers?o.modifiers[e]:{})})),this.modifiers=Object.keys(this.options.modifiers).map((function(t){return ct({name:t},i.options.modifiers[t])})).sort((function(t,e){return t.order-e.order})),this.modifiers.forEach((function(t){t.enabled&&z(t.onLoad)&&t.onLoad(i.reference,i.popper,i.options,t,i.state)})),this.update();var r=this.options.eventsEnabled;r&&this.enableEventListeners(),this.state.eventsEnabled=r}return ft(t,[{key:"update",value:function(){return At.call(this)}},{key:"destroy",value:function(){return Ot.call(this)}},{key:"enableEventListeners",value:function(){return Pt.call(this)}},{key:"disableEventListeners",value:function(){return Ft.call(this)}}]),t}();Vt.Utils=("undefined"!=typeof window?window:global).PopperUtils,Vt.placements=Bt,Vt.Defaults=Ut;var Yt=Vt,zt="dropdown",Kt="bs.dropdown",Xt=i.default.fn[zt],Gt=new RegExp("38|40|27"),$t="disabled",Jt="show",Zt="dropdown-menu-right",te="hide.bs.dropdown",ee="hidden.bs.dropdown",ne="click.bs.dropdown.data-api",ie="keydown.bs.dropdown.data-api",oe='[data-toggle="dropdown"]',re=".dropdown-menu",ae={offset:0,flip:!0,boundary:"scrollParent",reference:"toggle",display:"dynamic",popperConfig:null},se={offset:"(number|string|function)",flip:"boolean",boundary:"(string|element)",reference:"(string|element)",display:"string",popperConfig:"(null|object)"},le=function(){function t(t,e){this._element=t,this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}var e=t.prototype;return e.toggle=function(){if(!this._element.disabled&&!i.default(this._element).hasClass($t)){var e=i.default(this._menu).hasClass(Jt);t._clearMenus(),e||this.show(!0)}},e.show=function(e){if(void 0===e&&(e=!1),!(this._element.disabled||i.default(this._element).hasClass($t)||i.default(this._menu).hasClass(Jt))){var n={relatedTarget:this._element},o=i.default.Event("show.bs.dropdown",n),r=t._getParentFromElement(this._element);if(i.default(r).trigger(o),!o.isDefaultPrevented()){if(!this._inNavbar&&e){if("undefined"==typeof Yt)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");var a=this._element;"parent"===this._config.reference?a=r:u.isElement(this._config.reference)&&(a=this._config.reference,"undefined"!=typeof this._config.reference.jquery&&(a=this._config.reference[0])),"scrollParent"!==this._config.boundary&&i.default(r).addClass("position-static"),this._popper=new Yt(a,this._menu,this._getPopperConfig())}"ontouchstart"in document.documentElement&&0===i.default(r).closest(".navbar-nav").length&&i.default(document.body).children().on("mouseover",null,i.default.noop),this._element.focus(),this._element.setAttribute("aria-expanded",!0),i.default(this._menu).toggleClass(Jt),i.default(r).toggleClass(Jt).trigger(i.default.Event("shown.bs.dropdown",n))}}},e.hide=function(){if(!this._element.disabled&&!i.default(this._element).hasClass($t)&&i.default(this._menu).hasClass(Jt)){var e={relatedTarget:this._element},n=i.default.Event(te,e),o=t._getParentFromElement(this._element);i.default(o).trigger(n),n.isDefaultPrevented()||(this._popper&&this._popper.destroy(),i.default(this._menu).toggleClass(Jt),i.default(o).toggleClass(Jt).trigger(i.default.Event(ee,e)))}},e.dispose=function(){i.default.removeData(this._element,Kt),i.default(this._element).off(".bs.dropdown"),this._element=null,this._menu=null,null!==this._popper&&(this._popper.destroy(),this._popper=null)},e.update=function(){this._inNavbar=this._detectNavbar(),null!==this._popper&&this._popper.scheduleUpdate()},e._addEventListeners=function(){var t=this;i.default(this._element).on("click.bs.dropdown",(function(e){e.preventDefault(),e.stopPropagation(),t.toggle()}))},e._getConfig=function(t){return t=a({},this.constructor.Default,i.default(this._element).data(),t),u.typeCheckConfig(zt,t,this.constructor.DefaultType),t},e._getMenuElement=function(){if(!this._menu){var e=t._getParentFromElement(this._element);e&&(this._menu=e.querySelector(re))}return this._menu},e._getPlacement=function(){var t=i.default(this._element.parentNode),e="bottom-start";return t.hasClass("dropup")?e=i.default(this._menu).hasClass(Zt)?"top-end":"top-start":t.hasClass("dropright")?e="right-start":t.hasClass("dropleft")?e="left-start":i.default(this._menu).hasClass(Zt)&&(e="bottom-end"),e},e._detectNavbar=function(){return i.default(this._element).closest(".navbar").length>0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=a({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),a({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this).data(Kt);if(n||(n=new t(this,"object"==typeof e?e:null),i.default(this).data(Kt,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(oe)),o=0,r=n.length;o0&&a--,40===e.which&&adocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(pe);var o=u.getTransitionDurationFromElement(this._dialog);i.default(this._element).off(u.TRANSITION_END),i.default(this._element).one(u.TRANSITION_END,(function(){t._element.classList.remove(pe),n||i.default(t._element).one(u.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,o)})).emulateTransitionEnd(o),this._element.focus()}},e._showElement=function(t){var e=this,n=i.default(this._element).hasClass(ce),o=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),i.default(this._dialog).hasClass("modal-dialog-scrollable")&&o?o.scrollTop=0:this._element.scrollTop=0,n&&u.reflow(this._element),i.default(this._element).addClass(he),this._config.focus&&this._enforceFocus();var r=i.default.Event("shown.bs.modal",{relatedTarget:t}),a=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,i.default(e._element).trigger(r)};if(n){var s=u.getTransitionDurationFromElement(this._dialog);i.default(this._dialog).one(u.TRANSITION_END,a).emulateTransitionEnd(s)}else a()},e._enforceFocus=function(){var t=this;i.default(document).off(_e).on(_e,(function(e){document!==e.target&&t._element!==e.target&&0===i.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?i.default(this._element).on(ye,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||i.default(this._element).off(ye)},e._setResizeEvent=function(){var t=this;this._isShown?i.default(window).on(ve,(function(e){return t.handleUpdate(e)})):i.default(window).off(ve)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){i.default(document.body).removeClass(de),t._resetAdjustments(),t._resetScrollbar(),i.default(t._element).trigger(me)}))},e._removeBackdrop=function(){this._backdrop&&(i.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=i.default(this._element).hasClass(ce)?ce:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),i.default(this._backdrop).appendTo(document.body),i.default(this._element).on(be,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&u.reflow(this._backdrop),i.default(this._backdrop).addClass(he),!t)return;if(!n)return void t();var o=u.getTransitionDurationFromElement(this._backdrop);i.default(this._backdrop).one(u.TRANSITION_END,t).emulateTransitionEnd(o)}else if(!this._isShown&&this._backdrop){i.default(this._backdrop).removeClass(he);var r=function(){e._removeBackdrop(),t&&t()};if(i.default(this._element).hasClass(ce)){var a=u.getTransitionDurationFromElement(this._backdrop);i.default(this._backdrop).one(u.TRANSITION_END,r).emulateTransitionEnd(a)}else r()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},We={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Ue={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Ve=function(){function t(t,e){if("undefined"==typeof Yt)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=i.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),i.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(i.default(this.getTipElement()).hasClass(Fe))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),i.default.removeData(this.element,this.constructor.DATA_KEY),i.default(this.element).off(this.constructor.EVENT_KEY),i.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&i.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===i.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=i.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){i.default(this.element).trigger(e);var n=u.findShadowRoot(this.element),o=i.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!o)return;var r=this.getTipElement(),a=u.getUID(this.constructor.NAME);r.setAttribute("id",a),this.element.setAttribute("aria-describedby",a),this.setContent(),this.config.animation&&i.default(r).addClass(Pe);var s="function"==typeof this.config.placement?this.config.placement.call(this,r,this.element):this.config.placement,l=this._getAttachment(s);this.addAttachmentClass(l);var f=this._getContainer();i.default(r).data(this.constructor.DATA_KEY,this),i.default.contains(this.element.ownerDocument.documentElement,this.tip)||i.default(r).appendTo(f),i.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new Yt(this.element,r,this._getPopperConfig(l)),i.default(r).addClass(Fe),i.default(r).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&i.default(document.body).children().on("mouseover",null,i.default.noop);var d=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,i.default(t.element).trigger(t.constructor.Event.SHOWN),e===He&&t._leave(null,t)};if(i.default(this.tip).hasClass(Pe)){var c=u.getTransitionDurationFromElement(this.tip);i.default(this.tip).one(u.TRANSITION_END,d).emulateTransitionEnd(c)}else d()}},e.hide=function(t){var e=this,n=this.getTipElement(),o=i.default.Event(this.constructor.Event.HIDE),r=function(){e._hoverState!==Re&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),i.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(i.default(this.element).trigger(o),!o.isDefaultPrevented()){if(i.default(n).removeClass(Fe),"ontouchstart"in document.documentElement&&i.default(document.body).children().off("mouseover",null,i.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,i.default(this.tip).hasClass(Pe)){var a=u.getTransitionDurationFromElement(n);i.default(n).one(u.TRANSITION_END,r).emulateTransitionEnd(a)}else r();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){i.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||i.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(i.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),i.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=ke(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?i.default(e).parent().is(t)||t.empty().append(e):t.text(i.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return a({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=a({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:u.isElement(this.config.container)?i.default(this.config.container):i.default(document).find(this.config.container)},e._getAttachment=function(t){return Be[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)i.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Me?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,o=e===Me?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;i.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(o,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},i.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=a({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||i.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),i.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?qe:Me]=!0),i.default(e.getTipElement()).hasClass(Fe)||e._hoverState===Re?e._hoverState=Re:(clearTimeout(e._timeout),e._hoverState=Re,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===Re&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||i.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),i.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?qe:Me]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=He,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===He&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=i.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Le.indexOf(t)&&delete e[t]})),"number"==typeof(t=a({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),u.typeCheckConfig(Ie,t,this.constructor.DefaultType),t.sanitize&&(t.template=ke(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=i.default(this.getTipElement()),e=t.attr("class").match(je);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(i.default(t).removeClass(Pe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data(Oe),r="object"==typeof e&&e;if((o||!/dispose|hide/.test(e))&&(o||(o=new t(this,r),n.data(Oe,o)),"string"==typeof e)){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e]()}}))},r(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Qe}},{key:"NAME",get:function(){return Ie}},{key:"DATA_KEY",get:function(){return Oe}},{key:"Event",get:function(){return Ue}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return We}}]),t}();i.default.fn.tooltip=Ve._jQueryInterface,i.default.fn.tooltip.Constructor=Ve,i.default.fn.tooltip.noConflict=function(){return i.default.fn.tooltip=xe,Ve._jQueryInterface};var Ye="bs.popover",ze=i.default.fn.popover,Ke=new RegExp("(^|\\s)bs-popover\\S+","g"),Xe=a({},Ve.Default,{placement:"right",trigger:"click",content:"",template:''}),Ge=a({},Ve.DefaultType,{content:"(string|element|function)"}),$e={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Je=function(t){var e,n;function o(){return t.apply(this,arguments)||this}n=t,(e=o).prototype=Object.create(n.prototype),e.prototype.constructor=e,s(e,n);var a=o.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){i.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||i.default(this.config.template)[0],this.tip},a.setContent=function(){var t=i.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=i.default(this.getTipElement()),e=t.attr("class").match(Ke);null!==e&&e.length>0&&t.removeClass(e.join(""))},o._jQueryInterface=function(t){return this.each((function(){var e=i.default(this).data(Ye),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new o(this,n),i.default(this).data(Ye,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},r(o,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xe}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Ye}},{key:"Event",get:function(){return $e}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Ge}}]),o}(Ve);i.default.fn.popover=Je._jQueryInterface,i.default.fn.popover.Constructor=Je,i.default.fn.popover.noConflict=function(){return i.default.fn.popover=ze,Je._jQueryInterface};var Ze="scrollspy",tn="bs.scrollspy",en=i.default.fn[Ze],nn="active",on="position",rn=".nav, .list-group",an={offset:10,method:"auto",target:""},sn={offset:"number",method:"string",target:"(string|element)"},ln=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,i.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":on,n="auto"===this._config.method?e:this._config.method,o=n===on?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,r=u.getSelectorFromElement(t);if(r&&(e=document.querySelector(r)),e){var a=e.getBoundingClientRect();if(a.width||a.height)return[i.default(e)[n]().top+o,r]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){i.default.removeData(this._element,tn),i.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=a({},an,"object"==typeof t&&t?t:{})).target&&u.isElement(t.target)){var e=i.default(t.target).attr("id");e||(e=u.getUID(Ze),i.default(t.target).attr("id",e)),t.target="#"+e}return u.typeCheckConfig(Ze,t,sn),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",gn=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&i.default(this._element).hasClass(dn)||i.default(this._element).hasClass("disabled"))){var e,n,o=i.default(this._element).closest(".nav, .list-group")[0],r=u.getSelectorFromElement(this._element);if(o){var a="UL"===o.nodeName||"OL"===o.nodeName?mn:pn;n=(n=i.default.makeArray(i.default(o).find(a)))[n.length-1]}var s=i.default.Event("hide.bs.tab",{relatedTarget:this._element}),l=i.default.Event("show.bs.tab",{relatedTarget:n});if(n&&i.default(n).trigger(s),i.default(this._element).trigger(l),!l.isDefaultPrevented()&&!s.isDefaultPrevented()){r&&(e=document.querySelector(r)),this._activate(this._element,o);var f=function(){var e=i.default.Event("hidden.bs.tab",{relatedTarget:t._element}),o=i.default.Event("shown.bs.tab",{relatedTarget:n});i.default(n).trigger(e),i.default(t._element).trigger(o)};e?this._activate(e,e.parentNode,f):f()}}},e.dispose=function(){i.default.removeData(this._element,un),this._element=null},e._activate=function(t,e,n){var o=this,r=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?i.default(e).children(pn):i.default(e).find(mn))[0],a=n&&r&&i.default(r).hasClass(cn),s=function(){return o._transitionComplete(t,r,n)};if(r&&a){var l=u.getTransitionDurationFromElement(r);i.default(r).removeClass(hn).one(u.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._transitionComplete=function(t,e,n){if(e){i.default(e).removeClass(dn);var o=i.default(e.parentNode).find("> .dropdown-menu .active")[0];o&&i.default(o).removeClass(dn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}i.default(t).addClass(dn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u.reflow(t),t.classList.contains(cn)&&t.classList.add(hn);var r=t.parentNode;if(r&&"LI"===r.nodeName&&(r=r.parentNode),r&&i.default(r).hasClass("dropdown-menu")){var a=i.default(t).closest(".dropdown")[0];if(a){var s=[].slice.call(a.querySelectorAll(".dropdown-toggle"));i.default(s).addClass(dn)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data(un);if(o||(o=new t(this),n.data(un,o)),"string"==typeof e){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e]()}}))},r(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();i.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),gn._jQueryInterface.call(i.default(this),"show")})),i.default.fn.tab=gn._jQueryInterface,i.default.fn.tab.Constructor=gn,i.default.fn.tab.noConflict=function(){return i.default.fn.tab=fn,gn._jQueryInterface};var _n="bs.toast",vn=i.default.fn.toast,bn="hide",yn="show",En="showing",wn="click.dismiss.bs.toast",Tn={animation:!0,autohide:!0,delay:500},Cn={animation:"boolean",autohide:"boolean",delay:"number"},Sn=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=i.default.Event("show.bs.toast");if(i.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(En),t._element.classList.add(yn),i.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(bn),u.reflow(this._element),this._element.classList.add(En),this._config.animation){var o=u.getTransitionDurationFromElement(this._element);i.default(this._element).one(u.TRANSITION_END,n).emulateTransitionEnd(o)}else n()}},e.hide=function(){if(this._element.classList.contains(yn)){var t=i.default.Event("hide.bs.toast");i.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(yn)&&this._element.classList.remove(yn),i.default(this._element).off(wn),i.default.removeData(this._element,_n),this._element=null,this._config=null},e._getConfig=function(t){return t=a({},Tn,i.default(this._element).data(),"object"==typeof t&&t?t:{}),u.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;i.default(this._element).on(wn,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(bn),i.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(yn),this._config.animation){var n=u.getTransitionDurationFromElement(this._element);i.default(this._element).one(u.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data(_n);if(o||(o=new t(this,"object"==typeof e&&e),n.data(_n,o)),"string"==typeof e){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e](this)}}))},r(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Cn}},{key:"Default",get:function(){return Tn}}]),t}();i.default.fn.toast=Sn._jQueryInterface,i.default.fn.toast.Constructor=Sn,i.default.fn.toast.noConflict=function(){return i.default.fn.toast=vn,Sn._jQueryInterface},t.Alert=c,t.Button=b,t.Carousel=O,t.Collapse=W,t.Dropdown=le,t.Modal=Se,t.Popover=Je,t.Scrollspy=ln,t.Tab=gn,t.Toast=Sn,t.Tooltip=Ve,t.Util=u,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/ks_dashboard_ninja/static/description/js/jquery.slim.min.js b/ks_dashboard_ninja/static/description/js/jquery.slim.min.js new file mode 100644 index 000000000..36b4e1a13 --- /dev/null +++ b/ks_dashboard_ninja/static/description/js/jquery.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/ks_dashboard_ninja/static/images/selected.svg b/ks_dashboard_ninja/static/images/selected.svg new file mode 100644 index 000000000..9992817e0 --- /dev/null +++ b/ks_dashboard_ninja/static/images/selected.svg @@ -0,0 +1,4 @@ + + + + diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.js b/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.js new file mode 100644 index 000000000..930785a12 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.js @@ -0,0 +1,2184 @@ +/** @odoo-module **/ +import { Component, onWillStart, useState ,useEffect,onMounted, onPatched, onWillUpdateProps,useRef,} from "@odoo/owl"; +import {globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions'; +import { jsonrpc } from "@web/core/network/rpc_service"; +import { useService } from "@web/core/utils/hooks"; +import { formatFloat } from "@web/core/utils/numbers"; +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 } from "@web/core/utils/render"; + +export class Ksdashboardgraph extends Component{ + setup(){ + this.chart_container = {}; + this.actionService = useService("action"); + this._rpc = useService("rpc"); + this.state = useState({item_data:"",list_view_data:""}) + onMounted(() => this._update_view()); + onPatched(() => this.update_list_view()); + this.item = this.props.item + + 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.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(async(nextprops)=>{ + if(nextprops.ksdatefilter !='none'){ + await this.ksFetchUpdateItem(this.item.id) + } + if (Object.keys(nextprops.pre_defined_filter).length){ + if (nextprops.pre_defined_filter?.item_ids?.includes(this.item.id)){ + await this.ksFetchUpdateItem(this.item.id) + } + } + if (Object.keys(nextprops.custom_filter).length){ + if (nextprops.custom_filter?.item_ids?.includes(this.item.id)){ + await this.ksFetchUpdateItem(this.item.id) + } + } + + }) + useEffect(()=>{ + if (update_interval){ + const interval = setInterval(() => { + this.ksFetchUpdateItem(this.item.id); + }, update_interval); + return () => clearInterval(interval); + } + + }) + } + async ksFetchUpdateItem(item_id) { + var self = this; + await jsonrpc("/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.__owl__.parent.component.ksGetParamsForItemFetch(self.item.id) + ], + kwargs:{context:this.props.dashboard_data.context}, +// context: self.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] ; + // 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() + this.ksrenderfunnelchart($(this.ks_gridstack_container.el),this.item); + }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() + this.ksrendermapview($(this.ks_gridstack_container.el),this.item) + }else{ + $(this.ks_gridstack_container.el).find(".card-body").remove() + this.ks_render_graphs($(this.ks_gridstack_container.el),this.item) + } +// $(this.ks_gridstack_container.el).find(".ks_breadcrumb").addClass("d-none") +// $(this.ks_gridstack_container.el).find(".ks_chart_heading").removeClass("d-none") + + }.bind(this)); + } + + _update_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.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'); + } +// if (!this.item.ks_show_records) { +// $('ks_info').hide(); +// } + }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"){ + this.ksrenderfunnelchart($(this.ks_gridstack_container.el),this.item); + }else if(this.item.ks_dashboard_item_type == ("ks_map_view")){ + this.ksrendermapview($(this.ks_gridstack_container.el),this.item) + }else{ + this.ks_render_graphs($(this.ks_gridstack_container.el),this.item) + } + } + } + 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.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; + 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 = parseDateTime(date,{format: "MM-dd-yyyy HH:mm:ss"}); + list_view_data.data_rows[j]["data"][index] = formatDate(parsedDate, { format: localization.dateFormat }) + } else{ + let parsedDate = parseDateTime(date,{format: "MM-dd-yyyy HH:mm:ss"}); + 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.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, + 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 + } + + ks_render_graphs($ks_gridstack_container,item){ + var self =this; + if($ks_gridstack_container.find('.ks_chart_card_body').length){ + var graph_render = $ks_gridstack_container.find('.ks_chart_card_body'); + }else{ + $($ks_gridstack_container.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var graph_render = $ks_gridstack_container.find('.ks_chart_card_body'); + } + const chart_data = JSON.parse(item.ks_chart_data); + var ks_labels = chart_data['labels']; + var ks_data = chart_data.datasets; + + let data=[]; + if (ks_data && ks_labels){ + if (ks_data.length && ks_labels.length){ + for (let i=0 ; i10? "radial" : "circular", + centerX: am5.percent(80) + }) + } + else{ + rec.labels.template.setAll({forceHidden:true}) + } + rec.data.setAll(data) + if(item.ks_hide_legend == true && series){ + legend.data.setAll(rec.dataItems); + } + + rec.appear(1000, 100); + } + break; + case "ks_polarArea_chart": + case "ks_radar_view": + case "ks_flower_view": + case "ks_radialBar_chart": + var chart = root.container.children.push(am5radar.RadarChart.new(root, { + panX: false, + panY: false, + wheelX: "panX", + wheelY: "zoomX", + radius: am5.percent(80), +// layout: root.verticalLayout, + })); + + if (item.ks_dashboard_item_type == "ks_flower_view"){ + var xRenderer = am5radar.AxisRendererCircular.new(root, {}); + xRenderer.labels.template.setAll({ + radius: 10, + cellStartLocation: 0.2, + cellEndLocation: 0.8 + }); + }else if (item.ks_dashboard_item_type == "ks_radialBar_chart"){ + var xRenderer = am5radar.AxisRendererCircular.new(root, { + strokeOpacity: 0.1, + minGridDistance: 50 + }); + xRenderer.labels.template.setAll({ + radius: 23, + maxPosition: 0.98 + }); + }else{ + var xRenderer = am5radar.AxisRendererCircular.new(root, {}); + xRenderer.labels.template.setAll({ + radius: 10, + }); + } + if (item.ks_dashboard_item_type == "ks_radialBar_chart"){ + var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, { + renderer: xRenderer, + extraMax: 0.1, + tooltip: am5.Tooltip.new(root, {}) + })); + + var yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, { + categoryField: "category", + renderer: am5radar.AxisRendererRadial.new(root, { minGridDistance: 20 }) + })); + yAxis.get("renderer").labels.template.setAll({ + oversizedBehavior: "truncate", + textAlign: "center", + maxWidth: 150, + ellipsis: "..." + }); + }else{ + var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { + maxDeviation: 0, + categoryField: "category", + renderer: xRenderer, + tooltip: am5.Tooltip.new(root, {}) + })); + xAxis.data.setAll(data); + + var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, { + renderer: am5radar.AxisRendererRadial.new(root, {}) + })); + } + if (item.ks_dashboard_item_type == "ks_polarArea_chart"){ + for (let k = 0;k").text("No Data Available.")); + } + }else{ + $ks_gridstack_container.find('.ks_chart_card_body').append($("
").text("No Data Available.")); + } + } + ksrenderfunnelchart($ks_gridstack_container,item){ + var self =this; + if($ks_gridstack_container.find('.ks_chart_card_body').length){ + var funnelRender = $ks_gridstack_container.find('.ks_chart_card_body'); + }else{ + $($ks_gridstack_container.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var funnelRender = $ks_gridstack_container.find('.ks_chart_card_body'); + } + var funnel_data = JSON.parse(item.ks_chart_data); + if (funnel_data['labels'] && funnel_data['datasets']){ + var ks_labels = funnel_data['labels']; + var ks_data = funnel_data.datasets[0].data; + const ks_sortobj = Object.fromEntries( + ks_labels.map((key, index) => [key, ks_data[index]]), + ); + const keyValueArray = Object.entries(ks_sortobj); + keyValueArray.sort((a, b) => b[1] - a[1]); + + var data=[]; + if (keyValueArray.length){ + for (let i=0 ; i{ + rec.events.on("click",function(ev){ + if (item.ks_data_calculation_type === 'custom' && !self.ks_dashboard_data['ks_ai_dashboard']){ + self.onChartCanvasClick_funnel(ev,`${item.id}`, item) + } + }) + }) + }else{ + $ks_gridstack_container.find('.ks_chart_card_body').append($("
").text("No Data Available.")) + } + }else{ + $ks_gridstack_container.find('.ks_chart_card_body').append($("
").text("No Data Available.")) + } + return $ks_gridstack_container; + } + + onChartCanvasClick(evt) { + + var self = this; + this.ksUpdateDashboard = {}; + var item_id = $(evt.target).parent().data().itemId; +// $(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_breadcrumb").removeClass("d-none") + var chart_title = '#'+this.item.name + if (this.ksUpdateDashboard[item_id]) { + clearInterval(this.ksUpdateDashboard[item_id]); + delete self.ksUpdateDashboard[item_id]; + } + 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(function(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 + "]").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 + }) + $($(".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 + "]").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(); + self.ksrenderfunnelchart($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"),item_data); + }else{ + $(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove(); + self.ks_render_graphs($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"), item_data); + } + + } + }); + } + } + evt.stopPropagation(); + } + + async onChartCanvasClick_funnel(evt,item_id,item){ + var self = this; + this.ksUpdateDashboard = {}; + if (item_id in self.ksUpdateDashboard) { + clearInterval(self.ksUpdateDashboard[item_id]); + delete self.ksUpdateDashboard[item_id] + } + 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; + } +// }else{ + +// var activePoint = evt.target.dataItem.dataContext; +// } + if (activePoint) { + if (activePoint.category){ + for (let i=0 ; i= 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(function(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; +// $($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(last_index_id_name).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(".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(id_name).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"){ + self.ksrenderfunnelchart($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"),item_data); + }else{ + self.ks_render_graphs($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"), item_data); + } + } 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'; + 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 + }) + $($(".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(chart_name).addClass('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) +// $(self.$el.find('.ks_pager')).removeClass('d-none'); + var updateValue = self.ks_dashboard_data.ks_set_interval; + if (updateValue) { + var updateinterval = setInterval(function() { + self.ksFetchChartItem(item_id) + }, updateValue); + self.ksUpdateDashboard[item_id] = updateinterval; + } + } + + } 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(function(new_item_data) { + this.ks_dashboard_data.ks_item_data[id] = new_item_data[id]; + $($(".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", + }); +// var item_view = $($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + id + "]").children()[0]); +// self.prepare_list(); +// var $textAnswer = $(renderToElement('Ksdashboardlistview', { +// list_view_data : this.state.list_view_data, +// ks_list_view_type : self.ks_list_view_type, +// tmpl_list_type : self.tmpl_list_type, +// isDrill : self.isDrill, +// ks_breadcrumb : this.ks_breadcrumb +// })); +// item_view.find(".card-body").append($container); +// self.ksFetchChartItem(item_data.item_id) +// var ks_length = JSON.parse(item_data['ks_list_view_data']).data_rows.length +// if (new_item_data["ks_list_view_type"] === "ungrouped" && JSON.parse(item_data['ks_list_view_data']).data_rows.length) { +// item_view.find('.ks_pager').removeClass('d-none'); +// if (item.ks_record_count <= item.ks_pagination_limit) item_view.find('.ks_load_next').addClass('ks_event_offer_list'); +// item_view.find('.ks_value').text("1-" + JSON.parse(item_data['ks_list_view_data']).data_rows.length); +// } else { +// item_view.find('.ks_pager').addClass('d-none'); +// } + }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) + self.ksrenderfunnelchart($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else{ + $(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove(); + self.ks_render_graphs($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + id + "]"), item_data); + } + }.bind(this)); + } + + + async ksrendermapview($ks_map_view_tmpl,item){ + console.log("render") + var self =this; + if($ks_map_view_tmpl.find('.ks_chart_card_body').length){ + var mapRender = $ks_map_view_tmpl.find('.ks_chart_card_body'); + }else{ + $($ks_map_view_tmpl.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var mapRender = $ks_map_view_tmpl.find('.ks_chart_card_body'); + } + var map_data = JSON.parse(item.ks_chart_data); + var ks_data=[]; + let data = []; + let label_data = []; + let query_label_data = []; + let domain = []; + let partner_domain = []; + var partners = []; + if (map_data.groupByIds?.length){ + partners = map_data['partner'] + var partners_query = []; + partners_query = map_data['ks_partners_map'] + var ks_labels = map_data['labels']; + if (map_data.datasets.length){ + var ks_data = map_data.datasets[0].data; + } + if (item.ks_data_calculation_type === 'query'){ + for (let i=0 ; i").text("No Data Available.")) + } + }else{ + $ks_map_view_tmpl.find('.ks_chart_card_body').append($("
").text("No Data Available.")) + } +// }else{ +// $ks_map_view_tmpl.find('.ks_map_card_body').append($("
").text("Please select Groupby that has Address."))} + return $ks_map_view_tmpl; + } + + ksRenderChartColorOptions(e) { + var self = this; + if (!$(e.currentTarget).parent().hasClass('ks_date_filter_selected')) { + // FIXME : Correct this later. + var $parent = $(e.currentTarget).parent().parent(); + $parent.find('.ks_date_filter_selected').removeClass('ks_date_filter_selected') + $(e.currentTarget).parent().addClass('ks_date_filter_selected') + 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(function() { + 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'){ + self.ksrenderfunnelchart($(self.ks_gridstack_container.el),item_data); + }else{ + self.ks_render_graphs($(self.ks_gridstack_container.el),item_data); + } + }) + } + } + + 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 = self.__owl__.parent.component.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:context} + }).then(function(result) { + 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_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 = self.__owl__.parent.component.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', +// context: self.getContext(), + args: [parseInt(itemId), { + ks_intial_count: ks_intial_count, + offset: ks_offset, + }, parseInt(self.ks_dashboard_data.ks_dashboard_id), params], + kwargs:{context:context} + }).then(function(result) { + 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}, + ks_speak:{type:Function , Optional:true}, + +}; + +Ksdashboardgraph.template = "Ks_chart_list_container"; diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml b/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml new file mode 100644 index 000000000..38559a0a6 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_graphs/ks_dashboard_graphs.xml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + +
+
+ +
+
+
+ +
+ + + + +
+ + + +
+ + + + + +
+ + +
+
+ + +
+ + +
+ + + + + + +
+ +
+ + +
+ +
+ +
+ + + +
+ +
+
+
+

+

+
+
+ + +
+
+
+ +
+
+
+
+
+ + +
+
+ Export +
+
+ + Export to Excel +
+
+ + Export to CSV +
+ +
+ + Save as PDF +
+ + + Save as Image + +
+ + Export Item +
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.js b/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.js new file mode 100644 index 000000000..25633d2af --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.js @@ -0,0 +1,449 @@ +/** @odoo-module **/ +import { Component,useState ,onWillUpdateProps,useEffect,onMounted,useRef} 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 { jsonrpc } from "@web/core/network/rpc_service"; +import { _t } from "@web/core/l10n/translation"; + +export class Ksdashboardkpiview extends Component{ + file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'} + setup(){ + var self = this; + this._rpc = useService("rpc"); + this.actionService = useService("action"); + this.ks_kpi = useRef('ks_kpi') + 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.classname = '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.ksdatefilter !='none'){ + await this.ksFetchUpdateItem(this.item.id) + } + if (Object.keys(nextprops.pre_defined_filter).length){ + if (nextprops.pre_defined_filter?.item_ids?.includes(this.item.id)){ + await this.ksFetchUpdateItem(this.item.id) + } + } + if (Object.keys(nextprops.custom_filter).length){ + if (nextprops.custom_filter?.item_ids?.includes(this.item.id)){ + await this.ksFetchUpdateItem(this.item.id) + } + } + + + }) + useEffect(()=>{ + if (update_interval){ + const interval = setInterval(() => { + this.ksFetchUpdateItem(this.item.id); + }, update_interval); + return () => clearInterval(interval); + } + + }) + } + ksFetchUpdateItem(item_id) { + var self = this; + return jsonrpc("/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.__owl__.parent.component.ksGetParamsForItemFetch(self.item.id) + ], + 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.prepareKpiData() + }.bind(this)); + } + + + _update_view(){ + if(!this.kpi_data[1]){ + if (this.field.ks_target_view === "Progress Bar" && this.field.ks_goal_enable) { + $('#' + this.item.id).find('#ks_progressbar').val(parseInt(this.target_deviation)); + } + if (this.field.ks_goal_enable) { + if (this.state.item_info_kpi1.target_arrow == 'up') { + $('#' + this.item.id).find(".target_deviation").css({ + "color": "green", + }); + } else { + $('#' + this.item.id).find(".target_deviation").css({ + "color": "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) { + if (this.state.item_info_kpi1.pre_arrow == 'up') { + $('#' + this.item.id).find(".pre_deviation").css({ + "color": "green", + }); + } else { + $('#' + this.item.id).find(".pre_deviation").css({ + "color": "red", + }); + } + } + if ($('#' + this.item.id).find('.ks_target_previous').children().length !== 2) { + $('#' + this.item.id).find('.ks_target_previous').addClass('justify-content-center'); + } + }else{ + if(this.field.ks_data_comparison == 'Sum'){ + $('#' + this.item.id).find('.target_deviation').css({ + "color": this.state.item_info_kpi2.ks_color + }); + if (this.field.ks_target_view === "Progress Bar") { + $('#' + this.item.id).find('#ks_progressbar').val(parseInt(this.ks_target_deviation == Infinity || this.ks_target_deviation == -Infinity ? 0:this.ks_target_deviation)) + } + } + if(this.field.ks_data_comparison == 'Percentage'){ + $('#' + this.item.id).find('.target_deviation').css({ + "color": this.state.item_info_kpi2.ks_color + }); + if (this.field.ks_target_view === "Progress Bar") { + if (this.state.item_info_kpi2.count) $('#' + this.item.id).find('#ks_progressbar').val(parseInt(this.count == Infinity || this.count == -Infinity ? 0 :this.count)); + else $('#' + this.item.id).find('#ks_progressbar').val(0); + } + } + } + + $(this.ks_kpi.el).find('.ks_dashboarditem_id').css({ + "background-color": this.ks_rgba_background_color, + "color": this.ks_rgba_font_color, + }); + } + + 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() { + 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.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }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; + } + } +// parseInt(Math.round((count_1 / target_1) * 100)) ? formatInteger(Math.round((count_1 / target_1) * 100)) : "0" + 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.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}, + ks_speak:{type:Function , Optional:true}, +}; + +Ksdashboardkpiview.template = "Ksdashboardkpiview"; diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml b/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml new file mode 100644 index 000000000..9e6f8a354 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_kpi_view/ks_dashboard_kpi.xml @@ -0,0 +1,625 @@ + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+ + + +
+
+ + +
+ +
+ + +
+
+ + + +
+
+ + + + +
+ +
+ + +
+
+ + + +
+
+ + +
+
+ + + + + + + + +
+
+
+ +
+
+ +
+
+
+ +
+
+ vs Target +
+
+ + + + + + +
+
+
+ +
+
+ vs Prev +
+
+ + + + +
+
+
+
+ + + +
+ + + + + + + + + + + + +
+ + +
+
+ + + +
+
+
+ +
+
+ + + + + + + + +
+
+
+ +
+
+ + + / + + + +
+
+ + +
+
+ vs Target +
+
+ + + + + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + + + +
+ + +
+
+ + + +
+
+
+ +
+
+ + + + + + + + +
+
+
+ +
+
+ + + + / + + + +
+
+
+
+ +
+
+ % +
+
+ +
+
+ vs Prev +
+
+ + + + + +
+
+
+ +
+ + + + + + + + + + + + +
+ + +
+
+ + + +
+
+ +
+ +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.js b/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.js new file mode 100644 index 000000000..959584c27 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.js @@ -0,0 +1,232 @@ +///** @odoo-module **/ +//import { Component, onWillStart, useState ,useEffect, onMounted, onWillRender,useRef,onWillPatch, onRendered } from "@odoo/owl"; +//import { localization } from "@web/core/l10n/localization"; +//import { formatFloat } from "@web/core/utils/numbers"; +//import {formatDate,formatDateTime} from "@web/core/l10n/dates"; +//import {parseDateTime,parseDate,} from "@web/core/l10n/dates"; +//import { useService } from "@web/core/utils/hooks"; +//import { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs'; +// +//export class Ksdashboardlistview extends Component{ +// setup(){ +// super.setup(); +// this._rpc = useService("rpc"); +// onMounted(() => this._update_view()); +// this.state = useState({list_view_data:""}) +// this.item = this.props.item +// this.ks_dashboard_data = this.props.dashboard_data +// this.prepare_item(); +// var update_interval = this.props.dashboard_data.ks_set_interval +// useEffect(()=>{ +// if (update_interval){ +// const interval = setInterval(() => { +// this.ksFetchUpdateItem(this.item.id); +// }, update_interval); +// return () => clearInterval(interval); +// } +// +// }) +// } +// 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.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)); +// } +// _update_view(){ +// if (this.item.ks_pagination_limit < this.intial_count) { +// $('.ks_load_next').addClass('ks_event_offer_list'); +// } +// if (this.intial_count < this.item.ks_pagination_limit ) { +// $('.ks_load_next').addClass('ks_event_offer_list'); +// } +// if (this.item.ks_record_data_limit === this.item.ks_pagination_limit){ +// $('.ks_load_next').addClass('ks_event_offer_list'); +// } +// if (this.intial_count == 0){ +// $('.ks_pager').addClass('d-none'); +// } +// if (this.item.ks_pagination_limit==0){ +// $('.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'); +// } +// if (!this.item.ks_show_records) { +// $('#ks_item_info').hide(); +// } +// } +// +// 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; +// } +// +// onChartCanvasClick(evt) { +// +// var self = this; +// this.ksUpdateDashboard = {}; +// var item_id = $(evt.target).parent().data().itemId; +// if (this.ksUpdateDashboard[item_id]) { +// clearInterval(this.ksUpdateDashboard[item_id]); +// delete self.ksUpdateDashboard[item_id]; +// } +// 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(function(result) { +// if (result.ks_list_view_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_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(".card-body").empty(); +// $($(".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_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 $container = self.renderListViewData(item_data); +// $(self.$el.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; +// 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_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] +//// self._renderChart($(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]), item_data); +// $(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove(); +// Ksdashboardgraph.prototype.ks_render_graphs($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"), item_data); +// +// } +// }); +// } +// } +// evt.stopPropagation(); +// } +// +// prepare_item() { +// var self = this; +// 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; +// } +// +// var list_view_data = JSON.parse(this.item.ks_list_view_data), +// data_rows = list_view_data.data_rows, +// length = data_rows ? data_rows.length: false; +// this.ks_info = ks_description; +// this.ks_chart_title = this.item.name +// this.item_id = this.item.id +// this.count = '1-' + length +// this.offset = 1 +// this.intial_count = length +// this.ks_pager = true +// this.ks_company= this.item.ks_company +// this.calculation_type = this.ks_dashboard_data.ks_item_data[this.item_id].ks_data_calculation_type +// +// 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'){ +// list_view_data.data_rows[j]["data"][index] = formatDate(parseDate(date), { format: localization.dateFormat }) +// } else{ +// list_view_data.data_rows[j]["data"][index] = formatDateTime(parseDateTime(date), { 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.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_dashboard_data = this.ks_dashboard_data +//// this.item.$el = $ks_gridstack_container; +// +// } +//}; +//Ksdashboardlistview.components = { Ksdashboardgraph }; +//Ksdashboardlistview.props = { +// item: { type: Object, Optional:true}, +// dashboard_data: { type: Object, Optional:true}, +//}; +// +//Ksdashboardlistview.template = "Ksdashboardlistview"; +////registry.category("actions").add("ks_dashboard_ninja", Ksdashboardlistview); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml b/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml new file mode 100644 index 000000000..059d651e3 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_dashboard_list.xml @@ -0,0 +1,268 @@ + + + + +
+
+
+
+
+ +
+ + + +
+
+ +
+ + + + +
+ + + + + + + + + +
+ + +
+
+ +
+ + + +
+ +
+
+ +
+
+

+

+
+
+ + +
+
+
+ +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + No Data Present + +
+ + + + + + + + + + +
+ + + + + + +
+ +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_new_list_view.xml b/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_new_list_view.xml new file mode 100644 index 000000000..92f301d38 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_list_view/ks_new_list_view.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + No Data Present + +
+ + + + + + + + + + +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.js b/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.js new file mode 100644 index 000000000..4b809056c --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.js @@ -0,0 +1,218 @@ +/** @odoo-module **/ +import { Component, useState ,useEffect,onWillUpdateProps,useRef, onMounted} 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 { jsonrpc } from "@web/core/network/rpc_service"; +import { _t } from "@web/core/l10n/translation"; + +export class Ksdashboardtile extends Component{ + file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'} + + setup(){ + var self = this; + this._rpc = useService("rpc"); + this.actionService = useService("action"); + this.ks_tile = useRef('ks_tile'); + this.ks_container_class = 'grid-stack-item'; + 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.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 = '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.ksdatefilter !='none'){ + await this.ksFetchUpdateItem(this.item.id) + } + if (Object.keys(nextprops.pre_defined_filter).length){ + if (nextprops.pre_defined_filter?.item_ids?.includes(this.item.id)){ + await this.ksFetchUpdateItem(this.item.id) + } + } + if (Object.keys(nextprops.custom_filter).length){ + if (nextprops.custom_filter?.item_ids?.includes(this.item.id)){ + await this.ksFetchUpdateItem(this.item.id) + } + } + + }) + useEffect(()=>{ + if (update_interval){ + const interval = setInterval(() => { + this.ksFetchUpdateItem(this.item.id); + }, update_interval); + return () => clearInterval(interval); + } + }) + onMounted(()=>{ + if (this.ks_ai_analysis){ + $(this.ks_tile.el).find('.ks_dashboarditem_id').addClass('ks_ai_chart_body') + } + + }) + + } + + ksFetchUpdateItem(item_id) { + + var self = this; + return jsonrpc("/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.__owl__.parent.component.ksGetParamsForItemFetch(self.item.id) + ], + 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_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; +// if (this.item.ks_tv_play){ +// this.item.ksIsUser = false; +// } + 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.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }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}, + ks_speak:{type:Function , Optional:true}, +}; + +Ksdashboardtile.template = "ksdashboardtile"; diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml b/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml new file mode 100644 index 000000000..7b12e63b6 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_tile_view/ks_dashboard_tile.xml @@ -0,0 +1,1104 @@ + + + + + + + + + + + + + + + +
+ +
+ + +
+
+ + + + +
+
+ + +
+
+ + + + + + + + + + + + + +
+ + +
+
+ + + +
+ +
+
+ + + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+
+ + +
+ +
+ + +
+
+ + + +
+
+ + +
+
+ + + + + + + + + +
+ +
+
+ +
+
+ +
+
+ +
+ + + + + + + + + + + + +
+ + +
+
+ + + +
+
+
+ + +
+ +
+ + +
+
+ + + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + +
+ + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+
+ + +
+ +
+ + +
+
+ + + +
+
+ + +
+
+ + + + + + + + +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + + + + + + +
+ + +
+
+ + + +
+ +
+ +
+ + +
+ +
+ + +
+
+ + + +
+
+ + +
+
+ + + + + + + + +
+
+
+ +
+
+ +
+
+ + +
+ + + + + + + + + + + + + +
+ + +
+
+ + + +
+
+ +
+ + +
+ +
+ + +
+
+ + + +
+
+ + +
+ + +
+
+ +
+
+ +
+
+ +
+ + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + +
+ + +
+
+ + + +
+ +
+ +
+ + +
+
+ +
+ + +
+
+

Layout Coming Soon

+
+
+
+ + +
+

+

+
+
+ + +
+
+ +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.js b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.js new file mode 100644 index 000000000..8c5e00f66 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.js @@ -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 }; diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.xml b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.xml new file mode 100644 index 000000000..b9f7e76ed --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/editdialog.xml @@ -0,0 +1,28 @@ + + + + +
+ + +
+ + + + +
+
+ + + +
+ + +
+ + + + +
+
+
diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.js b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.js new file mode 100644 index 000000000..1068c436e --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.js @@ -0,0 +1,251 @@ +/** @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"; + +export class Ksdashboardtodo extends Component{ + setup(){ + super.setup(); + this._rpc = useService("rpc"); + this.dialogService = useService("dialog"); + this.state = useState({to_do_view_data : ""}) + this.item = this.props.item + this.ks_dashboard_data = this.props.dashboard_data + this.prepare_item(); + } + + + 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: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.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.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }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; + 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(); + if (content.length === 0){ + console.log("") + } + 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); + this._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}, +}; +Ksdashboardtodo.components = {Todoeditdialog, addtododialog} + +Ksdashboardtodo.template = "Ksdashboardtodo"; diff --git a/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml new file mode 100644 index 000000000..ffc11b7b2 --- /dev/null +++ b/ks_dashboard_ninja/static/src/components/ks_dashboard_to_do_item/ks_dashboard_to_do.xml @@ -0,0 +1,413 @@ + + + + + + +
+
+
+
+
+
+ +
+
+ + +
+ + + + + + + + + +
+ + +
+
+ +
+ + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + +
+
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + + + + +
+
+ + No Tasks Available + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + + + + +
+
+ + No Tasks Available + + +
+
+
+
+
+
+ +
+
+ No Tasks Available +
+
+
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/css/ks_ai_dash.css b/ks_dashboard_ninja/static/src/css/ks_ai_dash.css index 1a64590c4..c3c3f21ec 100644 --- a/ks_dashboard_ninja/static/src/css/ks_ai_dash.css +++ b/ks_dashboard_ninja/static/src/css/ks_ai_dash.css @@ -20,4 +20,33 @@ background:#f2f2f2; display: block; margin-left: auto; margin-top: -7em - } \ No newline at end of file + } +.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; +} diff --git a/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja.scss b/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja.scss index 79c8c906b..b7e3830c6 100644 --- a/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja.scss +++ b/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja.scss @@ -8,8 +8,8 @@ .ks_dashboard_main_content { overflow: auto; - height:100%; - margin-top:40px; + height: calc(100vh - 175px); + max-height:100%; } .ks_dashboard_ninja_header{ text-align : right; @@ -318,7 +318,7 @@ .ks_dashboard_item_main_body_l5{ text-align: center; - padding: 0 10px; + padding: 0 30px; display: flex; flex-direction: column; } @@ -383,7 +383,7 @@ margin-top:10px; } .welcome_note h3{ - font-size: 32px; + font-size: 26px; font-weight: bold; } .welcome_note h3 span{ @@ -391,18 +391,17 @@ margin-top:10px; } .welcome_note img { - width: 40px; + width: 30px; } - @media (max-width: 1075px){ .ks_dashboard_header_name { max-width: 100%; } .ks_dashboard_top_menu{ - margin-top: 10px !important; + margin-top: 10px; } - .ks_dashboard_top_menu.filter_design{ + .ks_dashboard_top_menu.filter_design{ margin-top: 0 !important; } @@ -440,9 +439,16 @@ margin-top:10px; .ks_date_input_fields{ display: flex; - align-items: center; +// 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; } @@ -481,14 +487,14 @@ ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } border-top-left-radius: 3px !important; } -.ks_btn_middle_child{ +#ks_btn_middle_child{ border-radius: 0 !important; height: 100%; margin-right:10px; } -.ks_btn_middle_child input, .ks_btn_last_child input { +#ks_btn_middle_child, #ks_btn_last_child { padding: inherit !important; } @@ -531,6 +537,7 @@ ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } #ks_dashboard_title{ position: absolute; left: 60px !important; + z-index: 1; } .ks_preview_item { @@ -567,30 +574,17 @@ ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } #ks_dashboard_title_label{ color: #777777; - font-size: 1.8rem; + font-size: 25px; } @media (max-width: 992px){ - - -.custom_filter_calender { background: #f3f7f0 !important; padding: 15px !important; padding-top: 0 !important; position: relative; z-index: 2;} -.custom_filter_calender .ks_dashboard_link{display:unset !important;width: 100% !important; margin-bottom: 10px !important} -.custom_filter_calender .apply-dashboard-date-filter { margin-left: 0 !important; } -.custom_filter_calender .ks_date_apply_clear_print, .custom_filter_calender .ks_date_filter_selection_input,.custom_filter_calender .ks_date_input_fields { display: unset !important; } -.custom_filter_calender .ks_btn_middle_child{margin-right:0 !important;margin: 10px 0 !important;} -.custom_filter_calender .ks_btn_last_child{margin-bottom:10px !important} -.welcome_note{display:none} .ks_dashboard_ninja_toggle_menu:before { content: "\f142"; } - .ks_dashboard_top_settings.dropdown.d-none.d-lg-block, .ks_dashboard_edit_layout.ks_edit_layout { - display: none !important; - } - .manage_width_threedots { width: calc(100% - 70px); } - .threedots_databox { min-width: 150px; } + #ks_dashboard_title_label{ - font-size: 1.5rem; + font-size: 25px; } #ks_dashboard_title{ @@ -666,23 +660,15 @@ ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } .button-50 { padding: 4px 15px; } - } -@media (max-width:767px){ - - .create_new_item_popup .ks-char-preview { - width: 100% !important; +@media (max-width: 350px) { + .ks_dashboard_item_button_container { + flex-wrap: wrap; + position: relative; + z-index: 11 } - .create_new_item_popup .o_group.row.align-items-start.col-lg-6 { - width: 100% !important; - padding: 20px 15px 0 !important; - } - .create_new_item_popup .ks_dashboard_ninja.ks_create_chart_body .o_notebook .nav{gap:5px !important} - } - - @media (max-width: 575px){ #ks_date_filter_selection{ display:none; @@ -697,33 +683,6 @@ ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } #print_dashboard{ display:none; } - #ks_dashboard_title_input { - width: 100%; -} -.filter_siderbar_flex ul.nav.nav-tabs.flex-row.flex-nowrap { - flex-wrap: wrap !important; -} -.ks-modal-body-inner .ks-modal-title{font-size:25px !important} -.ks-modal-title span{padding:0} -.generate_item_popup .o-autocomplete.dropdown, .generate_item_popup .o_field_selection{width:100% !important} -.generate_item_popup .ks-generateAI-body .o_inner_group.grid.col-lg-6 .o_cell .o_field_many2one_selection{position:inherit !important} -.ks-char-preview .ks-chart-inner, .ks-modal-body-inner{padding:15px !important} -.ks_dashboard_top_menu .ks_date_filter_selection_input .ks_date_selection_box .ks_date_filter_dropdown .fa{display:inline-block !important; font-size: 15px;} -.ks_dashboard_top_menu .ks_date_filter_selection_input .ks_date_selection_box .ks_date_filter_dropdown{padding:10px !important} -.owl-nav .owl-prev {left: -30px !important;} -.owl-nav .owl-next { right: -30px !important; } -.custom_filter_calender .apply-dashboard-date-filter, .custom_filter_calender .clear-dashboard-date-filter{min-width:115px !important} -} -@media (max-width: 350px) { - .ks_dashboard_item_button_container { - flex-wrap: wrap; - position: relative; - z-index: 11 - } - .ks_dashboard_top_menu .ks_dashboard_edit_mode_settings .ks_dashboard_cancel_layout{min-width: 100px !important;} - .ks_dashboard_top_menu .ks_dashboard_edit_mode_settings .oe_dashboard_links, .ks_dashboard_top_menu .ks_dashboard_edit_mode_settings .ks_dashboard_cancel_layout { - margin-left: 5px !important; -} } @@ -737,4 +696,17 @@ ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } .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; } \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_item.css b/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_item.css index 15a9e7072..5449d8d6a 100644 --- a/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_item.css +++ b/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_item.css @@ -30,7 +30,6 @@ .ks_image_widget_icon_container{ background : transparent; border: none; - margin: 5px; cursor: pointer; } @@ -154,21 +153,13 @@ width: 100%; bottom: 0; } -.ks-progress-bar { -padding: 0 20px 0 10px; -} -.ks-progress-bar-value { - padding-right: 10px; -} -.ks-progress-bar, .ks-progress-bar #ks_progressbar { - width:100%; -} + .ks_progress progress { background-color: #000; border: 0; - width: 100%; - height: 8px; - border-radius: 8px; + width: 80%; + height: 5px; + border-radius: 9px; } .ks_progress progress::-webkit-progress-bar { background-color: #000; @@ -197,9 +188,3 @@ padding: 0 20px 0 10px; .ks_map_card_body{ z-index:1; } -.ks_progress { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; -} \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_pro.css b/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_pro.css index 5204c52d2..60955697a 100644 --- a/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_pro.css +++ b/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja_pro.css @@ -72,13 +72,13 @@ } -/*.ks_chart_card_body{*/ -/* position: absolute;*/ -/* top: 53px;*/ -/* left: 8px;*/ -/* right: 8px;*/ -/* bottom: 8px;*/ -/*}*/ +.ks_chart_card_body{ + position: absolute; + top: 53px; + left: 8px; + right: 8px; + bottom: 8px; +} .ks_chart_card_body{ position: absolute; @@ -86,7 +86,6 @@ left: 8px; right: 8px; bottom: 8px; - /*max-height: 24rem;*/ } @@ -112,7 +111,6 @@ table#ksListViewTable { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - color: black; } .ks_dashboard_item_drill_up { @@ -124,12 +122,10 @@ table#ksListViewTable { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - color: black; } .ks_pager { min-width:98px; - color:black; } .ks_dashboard_item_hover:hover .ks_dashboard_item_header_hover > .ks_chart_inner_buttons{ @@ -167,7 +163,6 @@ table#ksListViewTable { .ksMaxTableContent{ max-height: 300px; - overflow: overlay; } @@ -211,7 +206,121 @@ table#ksListViewTable { .ks_date_filters_menu_drop_down { - /*max-height: 270px !important;*/ + max-height: 270px !important; overflow: auto !important; background-clip:unset; -} \ No newline at end of file +} +/*.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 + } \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/css/ks_flower_view.css b/ks_dashboard_ninja/static/src/css/ks_flower_view.css index e0be52d1c..8de26d5fb 100644 --- a/ks_dashboard_ninja/static/src/css/ks_flower_view.css +++ b/ks_dashboard_ninja/static/src/css/ks_flower_view.css @@ -1,7 +1,6 @@ -#chart2 { +#ks_flower_chart { width: 100%; - height: 500px; - background-color: white; + height: 300px; } #text { margin-left:70px; diff --git a/ks_dashboard_ninja/static/src/css/ks_funnel_view.css b/ks_dashboard_ninja/static/src/css/ks_funnel_view.css index 9f9f4ca63..7af881525 100644 --- a/ks_dashboard_ninja/static/src/css/ks_funnel_view.css +++ b/ks_dashboard_ninja/static/src/css/ks_funnel_view.css @@ -1,7 +1,6 @@ #chartdiv { width: 100%; - height: 400px; - background-color: white; + height: 300px; } #text { @@ -13,8 +12,8 @@ margin-right:25px; } -.funnel_text{ - font:3rem Lucida Grande; +.funnel_text , .graph_text{ + font:2rem Lucida Grande; align-items:center; display:flex; justify-content:center; diff --git a/ks_dashboard_ninja/static/src/css/ks_map_view.css b/ks_dashboard_ninja/static/src/css/ks_map_view.css index fabb35a85..23b1885a4 100644 --- a/ks_dashboard_ninja/static/src/css/ks_map_view.css +++ b/ks_dashboard_ninja/static/src/css/ks_map_view.css @@ -1,7 +1,6 @@ #map_chart { width: 100%; - height: 500px; - background-color: white; + height: 300px; } #text { margin-left:70px; @@ -13,7 +12,7 @@ } .map_text{ - font:3rem Lucida Grande; + font:2rem Lucida Grande; align-items:center; display:flex; justify-content:center; diff --git a/ks_dashboard_ninja/static/src/css/ks_radial_chart.css b/ks_dashboard_ninja/static/src/css/ks_radial_chart.css index 430034c96..313187718 100644 --- a/ks_dashboard_ninja/static/src/css/ks_radial_chart.css +++ b/ks_dashboard_ninja/static/src/css/ks_radial_chart.css @@ -1,7 +1,6 @@ -#chart1 { +#radial_chart { width: 100%; - height: 550px; - background-color: white; + height: 300px; } #text { diff --git a/ks_dashboard_ninja/static/src/css/ks_to_do_item.css b/ks_dashboard_ninja/static/src/css/ks_to_do_item.css index 063a066cb..5466b4e83 100644 --- a/ks_dashboard_ninja/static/src/css/ks_to_do_item.css +++ b/ks_dashboard_ninja/static/src/css/ks_to_do_item.css @@ -42,7 +42,7 @@ .ks_to_do_card_body .form-check { padding: 0; - margin: 0px; + margin: -22px 0 0; } .form-check .form-check-label { cursor: pointer; diff --git a/ks_dashboard_ninja/static/src/css/ks_toggle_icon.css b/ks_dashboard_ninja/static/src/css/ks_toggle_icon.css index 7f652286e..3a4d28853 100644 --- a/ks_dashboard_ninja/static/src/css/ks_toggle_icon.css +++ b/ks_dashboard_ninja/static/src/css/ks_toggle_icon.css @@ -148,15 +148,3 @@ border-top: 1px solid #dcdada; .ks_info_display { display: block !important; } - -/*.config_dropdown .dropdown-item, .config_dropdown .dropdown-item-studio { - padding: 6px 20px; - color: black; -} - -.btn-secondary.dropdown-toggle { - color: #FFF; - background-color: #FFF; - border-color: #FFF; - box-shadow: 0; -}*/ diff --git a/ks_dashboard_ninja/static/src/css/style.css b/ks_dashboard_ninja/static/src/css/style.css index 95acc9646..3130f206b 100644 --- a/ks_dashboard_ninja/static/src/css/style.css +++ b/ks_dashboard_ninja/static/src/css/style.css @@ -89,6 +89,21 @@ flex-flow: inherit !important; } +.o_list_renderer .o_list_table thead{ + /*background-color: #e9ecef;*/ + +} + + +.flex_column_datetimerow .apply-dashboard-date-filter{margin:0} + + + +.flex_column_datetimerow .o_datetime_input.o_input cursor-pointer{ + margin:5px 0; + padding:5px 0; +} + .ks_demo_header .welcome_note { margin-top: 0; } @@ -139,6 +154,10 @@ box-shadow: 0px 0px 1px 0px rgba(9, 30, 66, 0.31), 0px 10px 18px 0px rgba(9, 30, 66, 0.15); } +.ks_dn_create_chart :not(.s_popup)>.modal .modal-content{ + height:100vh; +} + .ks_dn_create_chart .o_dialog_container .modal-dialog { transform: translateX(100%); transition: all ease-in-out 0.8s; @@ -473,7 +492,7 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele font-weight: 600; border-bottom: solid 1px var(--ks-dn-gray-300); padding-bottom: 15px; - margin-bottom: 15px; + margin-bottom: 7px; } .ks-chart-inner .o_notebook, @@ -734,6 +753,7 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele [data-color-mode="ks-dn-dark"] .ks_dashboard_header { background: var(--ks-dn-gray-200) !important; border: 0 !important; + height:135px; } /*[data-color-mode="ks-dn-dark"] .welcome_note h3 { @@ -746,7 +766,7 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele } } -.ks_dn_create_chart .ks_dashboard_top_settings { +.ks_dn_create_chart .ks_dashboard_top_settings , .ks_new_button_div .ks_dashboard_top_settings{ text-align: right; margin-bottom: 10px; display: flex !important; @@ -754,7 +774,11 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele } .ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_dash, -.ks_dn_create_chart .ks_dashboard_top_settings .ks_add_item_type_button { +.ks_dn_create_chart .ks_dashboard_top_settings .ks_add_item_type_button, +.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_exp_dash, + .ks_new_button_div .ks_dashboard_top_settings #ks_ai_item_dash, + .ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_exp_dash, + .ks_new_button_div .ks_dashboard_top_settings .ks_add_item_type_button{ padding: 12px; border-radius: 8px; font-size: 14px; @@ -765,27 +789,42 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele transition: all 0.3s ease-in-out; } -.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_dash { +.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_dash, + .ks_new_button_div .ks_dashboard_top_settings #ks_ai_item_dash, + .ks_new_button_div .ks_dashboard_top_settings #ks_ai_item_exp_dash, + .ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_exp_dash + { background: var(--ks-dn-blue-400); display: flex; align-items: center; justify-content: center; } +#ks_ai_item_exp_dash{ + border-radius:6px; + margin-left:8px; + background: #1D4D94 !important; +} -.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_dash img { +.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_dash img, +.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_exp_dash img, +.ks_new_button_div .ks_dashboard_top_settings #ks_ai_item_dash img, +.ks_new_button_div .ks_dashboard_top_settings #ks_ai_item_exp_dash img{ margin-right: 8px; } -.ks_dn_create_chart .ks_dashboard_top_settings .ks_add_item_type_button { +.ks_dn_create_chart .ks_dashboard_top_settings .ks_add_item_type_button, + .ks_new_button_div .ks_dashboard_top_settings .ks_add_item_type_button { background: var(--ks-dn-primary-400); } -.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_dash:hover { +.ks_dn_create_chart .ks_dashboard_top_settings #ks_ai_item_dash:hover, + .ks_new_button_div .ks_dashboard_top_settings #ks_ai_item_dash:hover { background: var(--ks-dn-blue-700); } -.ks_dn_create_chart .ks_dashboard_top_settings .ks_add_item_type_button:hover { +.ks_dn_create_chart .ks_dashboard_top_settings .ks_add_item_type_button:hover, + .ks_new_button_div .ks_dashboard_top_settings .ks_add_item_type_button:hover{ background: var(--ks-dn-primary-700); } @@ -854,12 +893,13 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele .ks_dashboard_top_menu .ks_date_filter_selection_input .ks_date_selection_box .ks_date_filter_dropdown { border: solid 1px var(--ks-dn-gray-50); border-radius: 8px !important; - background: transparent; + background: var(--ks-dn-gray-200); color: var(--ks-dn-black-600); padding: 12px; transition: all 0.3s ease-in-out; } + .ks_dashboard_top_menu .ks_date_filter_selection_input .ks_date_selection_box .ks_date_filter_dropdown:hover { background: var(--ks-dn-gray-hover); } @@ -982,3 +1022,6 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele position: static; } } +.ks_chart_card_body{ + padding: 5px 5px !important; +} diff --git a/ks_dashboard_ninja/static/src/js/domainfix.js b/ks_dashboard_ninja/static/src/js/domainfix.js new file mode 100644 index 000000000..9153c2b68 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/domainfix.js @@ -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) + } +}; diff --git a/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js b/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js new file mode 100644 index 000000000..e775089ba --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js @@ -0,0 +1,472 @@ +/** @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 { 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 { strftimeToLuxonFormat } from "@web/core/l10n/dates"; +import { session } from "@web/session"; +import { download } from "@web/core/network/download"; +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 { 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'; + + +export class KsAIDashboardNinja extends Component { + + setup() { + this.actionService = useService("action"); + this.dialogService = useService("dialog"); + this.notification = useService("notification"); + this._rpc = useService("rpc"); + this.dialogService = useService("dialog"); + this.header = useRef("ks_dashboard_header"); + 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.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(''); + 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(){ + 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(); + $(document.querySelectorAll(".modal-header .btn-close")).remove(); + $(document.querySelectorAll(".modal-footer .o-default-button")).remove(); + $(document.querySelectorAll(".modal-header .btn-link")).addClass('d-none') + + } + + 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).parent().hasClass('ks_img_selected'))){ + $('#ks_ai_add_item').removeClass("d-none"); + $(ev.currentTarget).parent().addClass('ks_img_selected'); + $(ev.currentTarget).find(".ks_img_display").removeClass("d-none"); + this.ksSelectedgraphid.push(parseInt($(ev.currentTarget).parent()[0].id)); + }else{ + $(ev.currentTarget).parent().removeClass('ks_img_selected'); + $(ev.currentTarget).find(".ks_img_display").addClass("d-none") + const index = this.ksSelectedgraphid.indexOf(parseInt($(ev.currentTarget).parent()[0].id)); + this.ksSelectedgraphid.splice(index, 1); + } + }else{ + if(!($(ev.currentTarget).hasClass('ks_img_selected'))){ + $('#ks_ai_add_item').removeClass("d-none"); + $(ev.currentTarget).addClass('ks_img_selected'); + $(ev.currentTarget).find(".ks_img_display").removeClass("d-none"); + this.ksSelectedgraphid.push(parseInt($(ev.currentTarget).parent()[0].id)); + }else{ + $(ev.currentTarget).removeClass('ks_img_selected'); + $(ev.currentTarget).find(".ks_img_display").addClass("d-none") + const index = this.ksSelectedgraphid.indexOf(parseInt($(ev.currentTarget).parent()[0].id)); + this.ksSelectedgraphid.splice(index, 1); + } + } + + 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('ks_img_selected') + $(item).find('.ks_img_display').removeClass("d-none"); + this.ksSelectedgraphid.push(parseInt($(item).parent()[0].id)) + }); + document.querySelectorAll(".modal-body .ks_dashboard_kpi_dashboard").forEach((item) =>{ + $(item).parent().addClass('ks_img_selected') + $(item).find('.ks_img_display').removeClass("d-none"); + this.ksSelectedgraphid.push(parseInt($(item).parent()[0].id)) + }); + + + document.querySelectorAll(".modal-body .ks_dashboarditem_chart_container").forEach((item) =>{ + $(item).addClass('ks_img_selected') + $(item).find('.ks_img_display').removeClass("d-none"); + 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") + } + + onremoveallitems(){ + + document.querySelectorAll(".modal-body .ks_list_view_container").forEach((item) =>{ + $(item).removeClass('ks_img_selected') + $(item).find('.ks_img_display').addClass("d-none"); + }) + + document.querySelectorAll(".modal-body .ks_dashboard_kpi_dashboard").forEach((item) =>{ + $(item).parent().removeClass('ks_img_selected') + $(item).find('.ks_img_display').addClass("d-none"); + }); + + document.querySelectorAll(".modal-body .ks_dashboarditem_chart_container").forEach((item) =>{ + $(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") + } + + 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){ + console.log(true) + } + +} + + +KsAIDashboardNinja.components = { Ksdashboardtile,Ksdashboardgraph,Ksdashboardkpiview, Ksdashboardtodo}; +KsAIDashboardNinja.template = "ksaiDashboardNinjaHeader" +registry.category("actions").add("ks_ai_dashboard_ninja",KsAIDashboardNinja); diff --git a/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js b/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js new file mode 100644 index 000000000..a7634d407 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js @@ -0,0 +1,3848 @@ +odoo.define('ks_dashboard_ninja.ks_dashboard', function(require) { + "use strict"; + + var core = require('web.core'); + const { patch } = require('web.utils'); + const { WebClient } = require("@web/webclient/webclient"); +// var export = require('ks_dashboard_ninja.import_button'); + var Dialog = require('web.Dialog'); + var viewRegistry = require('web.view_registry'); + var _t = core._t; + var QWeb = core.qweb; + var utils = require('web.utils'); + var config = require('web.config'); + var framework = require('web.framework'); + var time = require('web.time'); + var datepicker = require("web.datepicker"); + + const session = require('web.session'); + var AbstractAction = require('web.AbstractAction'); + var ajax = require('web.ajax'); + var framework = require('web.framework'); + var field_utils = require('web.field_utils'); + var KsGlobalFunction = require('ks_dashboard_ninja.KsGlobalFunction'); + + var KsQuickEditView = require('ks_dashboard_ninja.quick_edit_view'); + const { loadBundle } = require('@web/core/assets'); + + + var KsDashboardNinja = AbstractAction.extend({ + // To show or hide top control panel flag. + hasControlPanel: false, + + dependencies: ['bus_service'], + + /** + * @override + */ + + jsLibs: [ + '/ks_dashboard_ninja/static/lib/js/Chart.bundle.min.js', + '/ks_dashboard_ninja/static/lib/js/gridstack-h5.js', + '/ks_dashboard_ninja/static/lib/js/chartjs-plugin-datalabels.js', + '/ks_dashboard_ninja/static/lib/js/pdfmake.min.js', + '/ks_dashboard_ninja/static/lib/js/vfs_fonts.js', + 'ks_dashboard_ninja/static/lib/js/Animated.js', + 'ks_dashboard_ninja/static/lib/js/worldLow.js', + 'ks_dashboard_ninja/static/lib/js/map.js', + 'ks_dashboard_ninja/static/lib/js/index.js', + 'ks_dashboard_ninja/static/lib/js/pdfmake.js', + 'ks_dashboard_ninja/static/lib/js/percent.js', + 'ks_dashboard_ninja/static/lib/js/pdf.min.js', + 'ks_dashboard_ninja/static/lib/js/print.min.js', + ], + cssLibs: ['/ks_dashboard_ninja/static/lib/css/Chart.css', + '/ks_dashboard_ninja/static/lib/css/Chart.min.css' + ], + + init: function(parent, state, params) { +// css_grid = $('.o_rtl').length>0 ? + this._super.apply(this, arguments); + this.reload_menu_option = { + reload: state.context.ks_reload_menu, + menu_id: state.context.ks_menu_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 + var l10n = _t.database.parameters; + this.form_template = 'ks_dashboard_ninja_template_view'; + this.date_format = time.strftime_to_moment_format(_t.database.parameters.date_format) + this.date_format = this.date_format.replace(/\bYY\b/g, "YYYY"); + this.datetime_format = time.strftime_to_moment_format((_t.database.parameters.date_format + ' ' + l10n.time_format)) + // 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 = state.params.ks_dashboard_id; + + this.gridstack_options = { + staticGrid:true, + float: false, + cellHeight: 80, + styleInHead : true, +// disableOneColumnMode: true, + + }; + if (config.device.isMobileDevice) { + this.gridstack_options.disableOneColumnMode = false + } + this.gridstackConfig = {}; + this.grid = false; + this.chartMeasure = {}; + this.chart_container = {}; + this.list_container = {}; + + + 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(''); + if(state.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.state = {} + this.state['user_context']=context + }, + + getContext: function() { + var self = this; + var context = { + ksDateFilterSelection: self.ksDateFilterSelection, + ksDateFilterStartDate: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + if(self.state['user_context']['ksDateFilterSelection'] !== undefined && self.ksDateFilterSelection !== 'l_none'){ + context = self.state['user_context'] + } + return Object.assign(context, session.user_context); + }, + + on_attach_callback: function() { + var self = this; + $.when(self.ks_fetch_items_data()).then(function(result){ + self.ksRenderDashboard(); + self.ks_set_update_interval(); + if (self.ks_dashboard_data.ks_item_data) { + self._ksSaveCurrentLayout(); + session.user_context['gridstack_config'] = self.ks_get_current_gridstack_config(); + } + }); + }, + + ks_set_update_interval: function() { + var self = this; + if (self.ks_dashboard_data.ks_item_data) { + + Object.keys(self.ks_dashboard_data.ks_item_data).forEach(function(item_id) { + var item_data = self.ks_dashboard_data.ks_item_data[item_id] + var updateValue = self.ks_dashboard_data.ks_set_interval; + if (updateValue) { + if (!(item_id in self.ksUpdateDashboard)) { + if (['ks_tile', 'ks_list_view', 'ks_kpi', 'ks_to_do'].indexOf(item_data['ks_dashboard_item_type']) >= 0) { + var ksItemUpdateInterval = setInterval(function() { + self.ksFetchUpdateItem(item_id) + }, updateValue); + } else { + var ksItemUpdateInterval = setInterval(function() { + self.ksFetchChartItem(item_id) + }, updateValue); + } + self.ksUpdateDashboard[item_id] = ksItemUpdateInterval; + } + } + }); + } + }, + + + on_detach_callback: function() { + var self = this; + self.ks_remove_update_interval(); + if (self.ksDashboardEditMode) self._ksSaveCurrentLayout(); + + self.ksDateFilterSelection = false; + self.ksDateFilterStartDate = false; + self.ksDateFilterEndDate = false; +// self.ks_fetch_data(); + }, + + ks_remove_update_interval: function() { + var self = this; + if (self.ksUpdateDashboard) { + Object.values(self.ksUpdateDashboard).forEach(function(itemInterval) { + clearInterval(itemInterval); + }); + self.ksUpdateDashboard = {}; + } + }, + + + events: { + 'click #ks_add_item_selection > li': 'onAddItemTypeClick', + 'click .ks_dashboard_add_layout': '_onKsAddLayoutClick', + 'click .ks_dashboard_edit_layout': '_onKsEditLayoutClick', + 'click .ks_dashboard_select_item': 'onKsSelectItemClick', + 'click .ks_dashboard_save_layout': '_onKsSaveLayoutClick', + 'click .ks_dashboard_create_new_layout': '_onKsCreateLayoutClick', + 'click .ks_dashboard_cancel_layout': '_onKsCancelLayoutClick', + 'click .ks_item_click': '_onKsItemClick', + 'click .ks_load_previous': 'ksLoadPreviousRecords', + 'click .ks_load_next': 'ksLoadMoreRecords', + // 'click .ks_dashboard_item_action': '_onKsItemActionClick', + 'click .ks_dashboard_item_customize': '_onKsItemCustomizeClick', + 'click .ks_dashboard_item_delete': '_onKsDeleteItemClick', + 'change .ks_dashboard_header_name': '_onKsInputChange', + 'click .ks_duplicate_item': 'onKsDuplicateItemClick', + 'click .ks_move_item': 'onKsMoveItemClick', + 'change .ks_input_import_item_button': 'ksImportItem', + 'click .ks_item_description':'ksstopclick', + 'click .ks_dashboard_menu_container': function(e) { + e.stopPropagation(); + }, + 'click .ks_qe_dropdown_menu': function(e) { + e.stopPropagation(); + }, + 'click .ks_chart_json_export': 'ksItemExportJson', + 'click .ks_dashboard_item_action': 'ksStopClickPropagation', + 'show.bs.dropdown .ks_dropdown_container': 'onKsDashboardMenuContainerShow', + 'hide.bs.dropdown .ks_dashboard_item_button_container': 'onKsDashboardMenuContainerHide', + + // Dn Filters Events + 'click .apply-dashboard-date-filter': '_onKsApplyDateFilter', + 'click .clear-dashboard-date-filter': '_onKsClearDateValues', + 'change #ks_start_date_picker': '_ksShowApplyClearDateButton', + 'change #ks_end_date_picker': '_ksShowApplyClearDateButton', + 'click .ks_date_filters_menu': '_ksOnDateFilterMenuSelect', + 'click #ks_item_info': 'ksOnListItemInfoClick', + 'click .ks_chart_color_options': 'ksRenderChartColorOptions', + 'click #ks_chart_canvas_id': 'onChartCanvasClick', + 'click .ks_list_canvas_click': 'onChartCanvasClick', + 'click .ks_dashboard_item_chart_info': 'onChartMoreInfoClick', + 'click .ks_chart_xls_csv_export': 'ksChartExportXlsCsv', + 'click .ks_chart_pdf_export': 'ksChartExportPdf', + + 'click .ks_dashboard_quick_edit_action_popup': 'ksOnQuickEditView', + 'click .ks_edit_map_form': 'ksOnQuickEditView', + 'click .ks_dashboard_item_drill_up': 'ksOnDrillUp', + + 'click .ks_dashboard_layout_event': '_ksOnDnLayoutMenuSelect', + 'click .ks_dashboard_set_current_layout': '_ksSetCurrentLayoutClick', + 'click .ks_dashboard_cancel_current_layout': '_ksSetDiscardCurrentLayoutClick', + 'click .ks_add_dashboard_item_on_empty' : 'ks_add_dashboard_item_on_empty', + 'click #dashboard_settings': 'ksOnDashboardSettingClick', + 'click #dashboard_delete': 'ksOnDashboardDeleteClick', + 'click #dashboard_create': 'ksOnDashboardCreateClick', + 'click #dashboard_export': 'ksOnDashboardExportClick', + 'click #dashboard_import': 'ksOnDashboardImportClick', + 'click #dashboard_duplicate': 'ksOnDashboardDuplicateClick', + 'click #ks_ai_item_dash' : 'createaidash', + 'click #create_ai_dashboard' :'createaidashboard' + }, + + + + ksOnDashboardDuplicateClick: function(ev){ + ev.preventDefault(); + var self= this; + var dashboard_id = this.ks_dashboard_id; + this._rpc({ + model: 'ks.dashboard.duplicate.wizard', + method: "DuplicateDashBoard", + args: [self.ks_dashboard_id], + }).then((result)=>{ + self.do_action(result) + + }); + + }, + + ksOnDashboardImportClick: function(ev){ + ev.preventDefault(); + var self = this; + var dashboard_id = this.ks_dashboard_id; + this._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'ks_open_import', + args: [dashboard_id], + kwargs: { + dashboard_id: dashboard_id + } + }).then((result)=>{ + self.do_action(result) + }); + }, + + ksOnDashboardExportClick: function(ev){ + ev.preventDefault(); + var self= this; + var dashboard_id = JSON.stringify(this.ks_dashboard_id); + this._rpc({ + 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, + } + framework.blockUI(); + self.getSession().get_file({ + url: '/ks_dashboard_ninja/export/dashboard_json', + data: { + data: JSON.stringify(data) + }, + complete: framework.unblockUI, + error: (error) => this.call('crash_manager', 'rpc_error', error), + }); + }); + }, + + ksOnDashboardSettingClick: function(ev){ +// ev.preventDefault(); +// var self = this; + +// this._rpc({ +// model: 'ks_dashboard_ninja.board', +// method: 'ks_open_setting', +// args: [dashboard_id], +// kwargs: { +// dashboard_id: dashboard_id +// } +// }).then((result)=>{ +// self.do_action(result) +// }); + var self= this; + var dashboard_id = this.ks_dashboard_id; + var action = { + name: _t('ks_open_setting'), + 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.do_action(action) + + }, + + ksOnDashboardDeleteClick: function(ev){ + ev.preventDefault(); + var dashboard_id = this.ks_dashboard_id; + var self= this; + this._rpc({ + model: 'ks.dashboard.delete.wizard', + method: "DeleteDashBoard", + args: [self.ks_dashboard_id], + }).then((result)=>{ + self.do_action(result); + }); + + }, + + ksOnDashboardCreateClick: function(ev){ + var self= this; +// this._rpc({ +// model: 'ks.dashboard.wizard', +// method: "CreateDashBoard", +// args: [''], +// }).then((result)=>{ +// self.do_action(result); +// }); + var 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', + } + self.do_action(action) + + }, + + + _ksOnDnLayoutMenuSelect: function(ev){ + var selected_layout_id = $(ev.currentTarget).data('ks_layout_id'); + this.ksOnLayoutSelection(selected_layout_id); + + }, + + ksOnLayoutSelection: function(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); + _(this.gridstackConfig).each((x,y)=>{ + self.grid.update(self.$el.find(".grid-stack-item[gs-id=" + y + "]")[0],{ x:x['x'], y:x['y'], w:x['w'], h:x['h'],autoPosition:false}); + }); + + +// this.ks_dashboard_data.ks_selected_board_id = layout_id; + this.$el.find("#ks_dashboard_layout_dropdown_container .ks_layout_selected").removeClass("ks_layout_selected"); + this.$el.find("li.ks_dashboard_layout_event[data-ks_layout_id='"+ layout_id + "']").addClass('ks_layout_selected'); + this.$el.find("#ks_dn_layout_button span:first-child").text(selected_layout_name); + this.$el.find(".ks_dashboard_top_menu .ks_dashboard_top_settings").addClass("ks_hide"); + this.$el.find(".ks_dashboard_top_menu .ks_am_content_element").addClass("ks_hide"); + this.$el.find(".ks_dashboard_layout_edit_mode_settings").removeClass("ks_hide"); + }, + + _ksSetCurrentLayoutClick: function(){ + var self = this; + this.ks_dashboard_data.ks_selected_board_id = this.$el.find("#ks_dashboard_layout_dropdown_container .ks_layout_selected").data('ks_layout_id'); + this.$el.find(".ks_dashboard_top_menu .ks_dashboard_top_settings").removeClass("ks_hide"); + this.$el.find(".ks_dashboard_top_menu .ks_am_content_element").removeClass("ks_hide"); + this.$el.find(".ks_dashboard_layout_edit_mode_settings").addClass("ks_hide"); +// $('#ks_dashboard_title_input').val(this.ks_dashboard_data.ks_child_boards[this.ks_dashboard_data.ks_selected_board_id][0]); + this.ks_dashboard_data.name = this.ks_dashboard_data.ks_child_boards[this.ks_dashboard_data.ks_selected_board_id][0]; + + this._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'update_child_board', + args: ['update', self.ks_dashboard_id, { + "ks_selected_board_id": this.ks_dashboard_data.ks_selected_board_id, + }], + }).then(function(){ + window.location.reload(); + }); + }, + + _ksSetDiscardCurrentLayoutClick: function(){ + this.ksOnLayoutSelection(this.ks_dashboard_data.ks_selected_board_id); + this.$el.find(".ks_dashboard_top_menu .ks_dashboard_top_settings").removeClass("ks_hide"); + this.$el.find(".ks_dashboard_top_menu .ks_am_content_element").removeClass("ks_hide"); + this.$el.find(".ks_dashboard_layout_edit_mode_settings").addClass("ks_hide"); + + }, + + + ksOnQuickEditView: function(e) { + var self = this; + var item_id = e.currentTarget.dataset.itemId; + var item_data = this.ks_dashboard_data.ks_item_data[item_id]; + var item_el = $.find('[gs-id=' + item_id + ']'); + var $quickEditButton = $(QWeb.render('ksQuickEditButtonContainer', { + grid: $.extend({}, item_el[0].gridstackNode) + })); + $(item_el).before($quickEditButton); + + var ksQuickEditViewWidget = new KsQuickEditView.QuickEditView(this, { + item: item_data, + }); + + ksQuickEditViewWidget.appendTo($quickEditButton.find('.dropdown-menu')); + + ksQuickEditViewWidget.on("canBeDestroyed", this, function(result) { + if (ksQuickEditViewWidget) { + ksQuickEditViewWidget = false; + $quickEditButton.find('.ks_dashboard_item_action').click(); + } + }); + + ksQuickEditViewWidget.on("canBeRendered", this, function(result) { + $quickEditButton.find('.ks_dashboard_item_action').click(); + }); + + ksQuickEditViewWidget.on("openFullItemForm", this, function(result) { + ksQuickEditViewWidget.destroy(); + $quickEditButton.find('.ks_dashboard_item_action').click(); + self.ks_open_item_form_page(parseInt(item_id)); + }); + + + $quickEditButton.on("hide.bs.dropdown", function(ev) { + try { + if (ev.hasOwnProperty("clickEvent") && document.contains(ev.clickEvent.target) && !$(event.path[2]).hasClass('ui-menu ui-widget ui-widget-content ui-autocomplete dropdown-menu ui-front')) { + if (ksQuickEditViewWidget) { + ksQuickEditViewWidget.ksDiscardChanges(); + ksQuickEditViewWidget = false; + self.ks_set_update_interval(); + $quickEditButton.remove(); + } else { + self.ks_set_update_interval(); + $quickEditButton.remove(); + } + } else if (!ev.hasOwnProperty("clickEvent")) { + self.ks_set_update_interval(); + $quickEditButton.remove(); + } else { + return false; + } + } + catch(e) { + return false; + } + }); + + $quickEditButton.on("show.bs.dropdown", function() { + self.ks_remove_update_interval(); + }); + + e.stopPropagation(); + }, + + willStart: function() { + 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(this), this._super()).then(function() { + return self.ks_fetch_data(); + }); + }, + + start: function() { + var self = this; + self.ks_set_default_chart_view(); + return this._super() + }, + + ks_set_default_chart_view: function() { + Chart.plugins.unregister(ChartDataLabels); + var backgroundColor = 'white'; + Chart.plugins.register({ + beforeDraw: function(c) { + var ctx = c.chart.ctx; + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, c.chart.width, c.chart.height); + } + }); + Chart.plugins.register({ + afterDraw: function(chart) { + if (chart.data.labels.length === 0) { + // No data is present + var ctx = chart.chart.ctx; + var width = chart.chart.width; + var height = chart.chart.height + chart.clear(); + + ctx.save(); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.font = "3rem 'Lucida Grande'"; + ctx.fillText('No data available', width / 2, height / 2); + ctx.restore(); + } + } + + }); + + Chart.Legend.prototype.afterFit = function() { + var chart_type = this.chart.config.type; + if (chart_type === "pie" || chart_type === "doughnut") { + this.height = this.height; + } else { + this.height = this.height + 20; + }; + }; + }, + + ksFetchUpdateItem: function(item_id) { + var self = this; + return self._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'ks_fetch_item', + args: [ + [parseInt(item_id)], self.ks_dashboard_id, self.ksGetParamsForItemFetch(parseInt(item_id)) + ], + context: self.getContext(), + }).then(function(new_item_data) { + this.ks_dashboard_data.ks_item_data[item_id] = new_item_data[item_id]; + this.ksUpdateDashboardItem([item_id]); + }.bind(this)); + }, + + ksRenderChartColorOptions: function(e) { + var self = this; + if (!$(e.currentTarget).parent().hasClass('ks_date_filter_selected')) { + // FIXME : Correct this later. + var $parent = $(e.currentTarget).parent().parent(); + $parent.find('.ks_date_filter_selected').removeClass('ks_date_filter_selected') + $(e.currentTarget).parent().addClass('ks_date_filter_selected') + var item_data = self.ks_dashboard_data.ks_item_data[$parent.data().itemId]; + var chart_data = JSON.parse(item_data.ks_chart_data); + if(item_data.ks_dashboard_item_type != "ks_funnel_chart" && item_data.ks_dashboard_item_type != "ks_bullet_chart" && item_data.ks_dashboard_item_type != "ks_flower_view" && item_data.ks_dashboard_item_type != "ks_radialBar_chart"){ + this.ksChartColors(e.currentTarget.dataset.chartColor, this.chart_container[$parent.data().itemId], $parent.data().chartType, $parent.data().chartFamily, item_data.ks_bar_chart_stacked, item_data.ks_semi_circle_chart, item_data.ks_show_data_value, chart_data, item_data) + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [$parent.data().itemId, { + "ks_chart_item_color": e.currentTarget.dataset.chartColor + }], + }).then(function() { + self.ks_dashboard_data.ks_item_data[$parent.data().itemId]['ks_chart_item_color'] = e.currentTarget.dataset.chartColor; + }); + }else if (item_data.ks_dashboard_item_type == "ks_funnel_chart" ||item_data.ks_dashboard_item_type == "ks_bullet_chart"){ + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [$parent.data().itemId, { + "ks_funnel_item_color": e.currentTarget.dataset.chartColor + }], + }).then(function() { + self.ks_dashboard_data.ks_item_data[$parent.data().itemId]['ks_funnel_item_color'] = e.currentTarget.dataset.chartColor; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove(); + if(item_data.ks_dashboard_item_type == "ks_funnel_chart"){ + self.ksrenderfunnelchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data.ks_dashboard_item_type == "ks_bullet_chart"){ + self.ksrenderbulletchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + } + }); + }else if (item_data.ks_dashboard_item_type == "ks_flower_view"){ + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [$parent.data().itemId, { + "ks_flower_item_color": e.currentTarget.dataset.chartColor + }], + }).then(function() { + self.ks_dashboard_data.ks_item_data[$parent.data().itemId]['ks_flower_item_color'] = e.currentTarget.dataset.chartColor; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove(); + self.ksrenderflowerchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }); + }else if (item_data.ks_dashboard_item_type == "ks_radialBar_chart"){ + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [$parent.data().itemId, { + "ks_radial_item_color": e.currentTarget.dataset.chartColor + }], + }).then(function() { + self.ks_dashboard_data.ks_item_data[$parent.data().itemId]['ks_radial_item_color'] = e.currentTarget.dataset.chartColor; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove(); + self.ksrenderradialchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }); + } + } + }, + + //To fetch dashboard data. + ks_fetch_data: function() { + var self = this; + return this._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'ks_fetch_dashboard_data', + args: [self.ks_dashboard_id], + context: self.getContext(), + }).then(function(result) { +// result = self.normalize_dn_data(result); + self.ks_dashboard_data = result; + if(self.state['domain_data'] != undefined){ + self.ks_dashboard_data.ks_dashboard_domain_data=self.state['domain_data'] + Object.values(self.ks_dashboard_data.ks_dashboard_pre_domain_filter).map((x)=>{ + if(self.state['domain_data'][x['model']] != undefined){ + if(self.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; + } + }) + } + }); + }, + + normalize_dn_data: function(result){ + _(result.ks_child_boards).each((x,y)=>{if (typeof(y)==='number'){ + result[y.toString()] = result[y]; + delete result[y]; + }}) + return result; + }, + + ks_fetch_items_data: function(){ + var self = this; + var items_promises = [] + self.ks_dashboard_data.ks_dashboard_items_ids.forEach(function(item_id){ + items_promises.push(self._rpc({ + model: "ks_dashboard_ninja.board", + method: "ks_fetch_item", + context: self.getContext(), + args : [[item_id], self.ks_dashboard_id, self.ksGetParamsForItemFetch(item_id)] + }).then(function(result){ + self.ks_dashboard_data.ks_item_data[item_id] = result[item_id]; + })); + }); + + return Promise.all(items_promises) + }, + + ksGetParamsForItemFetch: function(){ + return {}; + }, + + on_reverse_breadcrumb: function(state) { + var self = this; + self.trigger_up('push_state', { + controllerID: this.controllerID, + state: state || {}, + }); + return $.when(self.ks_fetch_data()); + }, + + ksstopclick:function(e) { + this.ksAllowItemClick = false;; + + }, + + ksStopClickPropagation: function(e) { + this.ksAllowItemClick = false; + }, + + onKsDashboardMenuContainerShow: function(e) { + $(e.currentTarget).addClass('ks_dashboard_item_menu_show'); + var item_id = e.currentTarget.dataset.item_id; + if (this.ksUpdateDashboard[item_id]){ + clearInterval(this.ksUpdateDashboard[item_id]); + delete this.ksUpdateDashboard[item_id] + } + + // Dynamic Bootstrap menu populate Image Report + if ($(e.target.parentElement).hasClass('ks_dashboard_more_action')) { + var chart_id = e.target.parentElement.dataset.itemId; + var name = this.ks_dashboard_data.ks_item_data[chart_id].name; + var base64_image + if(this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_bullet_chart" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_funnel_chart" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_flower_view" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_radialBar_chart" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_map_view"){ + base64_image = (this.chart_container[chart_id].root.dom).querySelector("canvas").toDataURL("image/png") + }else{ + base64_image = this.chart_container[chart_id].toBase64Image(); + } + $(e.target.parentElement).find('.dropdown-menu').empty(); + $(e.target.parentElement).find('.dropdown-menu').append($(QWeb.render('ksMoreChartOptions', { + href: base64_image, + download_fileName: name, + chart_id: chart_id + }))) + } + }, + + + onKsDashboardMenuContainerHide: function(e) { + var self = this; + $(e.currentTarget).removeClass('ks_dashboard_item_menu_show'); + var item_id = e.currentTarget.dataset.item_id; + var updateValue = self.ks_dashboard_data.ks_set_interval; + if (updateValue) { + var updateinterval = setInterval(function() { + self.ksFetchUpdateItem(item_id) + }, updateValue); + self.ksUpdateDashboard[item_id] = updateinterval; + } + if (this.ks_dashboard_data.ks_item_data[item_id]['isDrill'] == true) { + clearInterval(this.ksUpdateDashboard[item_id]); + } + }, + + ks_get_dark_color: function(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; + }, + + + // This is to convert color #value into RGB format to add opacity value. + _ks_get_rgba_format: function(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] + ")"; + }, + + ksRenderDashboard: function() { + var self = this; + self.$el.empty(); + self.$el.addClass('ks_dashboard_ninja d-flex flex-column'); + var dash_name = $('ul[id="ks_dashboard_layout_dropdown_container"] li[class="ks_dashboard_layout_event ks_layout_selected"] span').text() + 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]; + var $ks_header = $(QWeb.render('ksDashboardNinjaHeader', { + ks_dashboard_name: self.ks_dashboard_data.name, + ks_multi_layout: self.ks_dashboard_data.multi_layouts, + ks_dash_name: self.ks_dashboard_data.name, + ks_dashboard_manager: self.ks_dashboard_data.ks_dashboard_manager, + date_selection_data: self.ks_date_filter_selections, + date_selection_order: self.ks_date_filter_selection_order, + ks_show_create_layout_option: (Object.keys(self.ks_dashboard_data.ks_item_data).length > 0) && self.ks_dashboard_data.ks_dashboard_manager, + ks_show_layout: self.ks_dashboard_data.ks_dashboard_manager && self.ks_dashboard_data.ks_child_boards && true, + ks_selected_board_id: self.ks_dashboard_data.ks_selected_board_id, + ks_child_boards: self.ks_dashboard_data.ks_child_boards, + ks_dashboard_data: self.ks_dashboard_data, + ks_dn_pre_defined_filters: _(self.ks_dashboard_data.ks_dashboard_pre_domain_filter).values().sort(function(a, b){return a.sequence - b.sequence}), + })); + + if (!config.device.isMobile) { + $ks_header.addClass("ks_dashboard_header_sticky") + } + + self.$el.append($ks_header); + if (Object.keys(self.ks_dashboard_data.ks_item_data).length===0){ + self.$el.find('.ks_dashboard_link').addClass("d-none"); + self.$el.find('.ks_dashboard_edit_layout').addClass("d-none"); + } + self.ksRenderDashboardMainContent(); + if (Object.keys(self.ks_dashboard_data.ks_item_data).length === 0) { + self._ksRenderNoItemView(); + } + + }, + + ksRenderDashboardMainContent: function() { + var self = this; + if (config.device.isMobile && $('#ks_dn_layout_button :first-child').length > 0) { + $('.ks_am_element').append($('#ks_dn_layout_button :first-child')[0].innerText); + this.$el.find("#ks_dn_layout_button").addClass("ks_hide"); + } + if (self.ks_dashboard_data.ks_item_data) { + self._renderDateFilterDatePicker(); + + self.$el.find('.ks_dashboard_link').removeClass("ks_hide"); + + $('.ks_dashboard_items_list').remove(); + var $dashboard_body_container = $(QWeb.render('ks_main_body_container')) + var $gridstackContainer = $dashboard_body_container.find(".grid-stack"); + $dashboard_body_container.appendTo(self.$el) + self.grid = GridStack.init(self.gridstack_options,$gridstackContainer[0]); + var items = self.ksSortItems(self.ks_dashboard_data.ks_item_data); + + self.ksRenderDashboardItems(items); + + // In gridstack version 0.3 we have to make static after adding element in dom + self.grid.setStatic(true); + + } else if (!self.ks_dashboard_data.ks_item_data) { + self.$el.find('.ks_dashboard_link').addClass("ks_hide"); + self._ksRenderNoItemView(); + } + }, + + // This function is for maintaining the order of items in mobile view + ksSortItems: function(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)); + }, + + ksRenderDashboardItems: function(items) { + var self = this; + self.$el.find('.print-dashboard-btn').addClass("ks_pro_print_hide"); + if (self.ks_dashboard_data.ks_gridstack_config) { + self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_gridstack_config); + } + var item_view; + var ks_container_class = 'grid-stack-item', + ks_inner_container_class = 'grid-stack-item-content'; + for (var i = 0; i < items.length; i++) { + if (self.grid) { + + if (items[i].ks_dashboard_item_type === 'ks_tile') { + var item_view = self._ksRenderDashboardTile(items[i]) + if (items[i].id in self.gridstackConfig) { + self.grid.addWidget($(item_view)[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h,autoPosition:true,minW:2,maxW:null,minH:2,maxH:null,id:items[i].id}); + } else { + self.grid.addWidget($(item_view)[0], {x:0, y:0, w:4, h:2,autoPosition:true,minW:2,maxW:null,minH:2,maxH:2,id:items[i].id}); + } + } else if (items[i].ks_dashboard_item_type === 'ks_list_view') { + self._renderListView(items[i], self.grid) + }else if (items[i].ks_dashboard_item_type === 'ks_kpi') { + var kpi_preview = self.renderKpi(items[i], self.grid) + if (items[i].id in self.gridstackConfig) { + self.grid.addWidget($kpi_preview[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h,autoPosition:true,minW:2,maxW:null,minH:2,maxH:null,id:items[i].id}); + } else { + self.grid.addWidget($kpi_preview[0], {x:0, y:0, w:3, h:2,autoPosition:true,minW:2,maxW:null,minH:2,maxH:null,id:items[i].id}); + } + + }else { + self._renderGraph(items[i], self.grid) + } + } + } + }, + + _ksMainBodyStyle: function(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 + }; + }, + + _ksRenderDashboardTile: function(tile) { + var self = this; + var ks_container_class = 'grid-stack-item'; + var ks_inner_container_class = 'grid-stack-item-content'; + 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 (tile.ks_multiplier_active){ + var ks_record_count = tile.ks_record_count * tile.ks_multiplier + if (tile.ks_unit){ + var ks_selection = tile.ks_unit_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = tile.ks_currency_id; + var ks_data = KsGlobalFunction._onKsGlobalFormatter(ks_record_count, tile.ks_data_formatting, tile.ks_precision_digits); + ks_data = KsGlobalFunction.ks_monetary(ks_data, ks_currency_id); + var data_count = ks_data; + } else{ + var ks_field = tile.ks_chart_unit; + var data_count= ks_field+" "+KsGlobalFunction._onKsGlobalFormatter(ks_record_count, tile.ks_data_formatting, tile.ks_precision_digits); + }}else { + var data_count= KsGlobalFunction._onKsGlobalFormatter(ks_record_count, tile.ks_data_formatting, tile.ks_precision_digits); + } + var count = ks_record_count; + }else{ + var ks_record_count = tile.ks_record_count + if (tile.ks_unit){ + var ks_selection = tile.ks_unit_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = tile.ks_currency_id; + var ks_data = KsGlobalFunction._onKsGlobalFormatter(ks_record_count, tile.ks_data_formatting, tile.ks_precision_digits); + ks_data = KsGlobalFunction.ks_monetary(ks_data, ks_currency_id); + var data_count = ks_data; + } else{ + var ks_field = tile.ks_chart_unit; + var data_count= ks_field+" "+KsGlobalFunction._onKsGlobalFormatter(ks_record_count, tile.ks_data_formatting, tile.ks_precision_digits); + }}else { + var data_count= KsGlobalFunction._onKsGlobalFormatter(ks_record_count, tile.ks_data_formatting, tile.ks_precision_digits); + } + var count = ks_record_count; + } + + + if (tile.ks_icon_select == "Custom") { + if (tile.ks_icon[0]) { + ks_icon_url = 'data:image/' + (self.file_type_magic_word[tile.ks_icon[0]] || 'png') + ';base64,' + tile.ks_icon; + } else { + ks_icon_url = false; + } + } + + + tile.ksIsDashboardManager = self.ks_dashboard_data.ks_dashboard_manager; + tile.ksIsUser = true; + if (tile.ks_tv_play){ + tile.ksIsUser = false; + } + ks_rgba_background_color = self._ks_get_rgba_format(tile.ks_background_color); + ks_rgba_font_color = self._ks_get_rgba_format(tile.ks_font_color); + ks_rgba_default_icon_color = self._ks_get_rgba_format(tile.ks_default_icon_color); + ks_rgba_button_color = self._ks_get_rgba_format(tile.ks_button_color); + if (tile.ks_info){ + var ks_description = tile.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } +// style_main_body = "background-color:" + ks_rgba_background_color + ";color : " + ks_rgba_font_color + ";"; + style_main_body = this._ksMainBodyStyle(ks_rgba_background_color, ks_rgba_font_color, tile).background_style; + switch (tile.ks_layout) { + case 'layout1': + item_view = QWeb.render('ks_dashboard_item_layout1', { + item: tile, + style_main_body: style_main_body, + ks_icon_url: ks_icon_url, + ks_rgba_default_icon_color: ks_rgba_default_icon_color, + ks_rgba_button_color:ks_rgba_button_color, + ks_container_class: ks_container_class, + ks_inner_container_class: ks_inner_container_class, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + data_count: data_count, + count: count, + ks_info: ks_description, + }); + break; + + case 'layout2': +// var ks_rgba_dark_background_color_l2 = self._ks_get_rgba_format(self.ks_get_dark_color(tile.ks_background_color.split(',')[0], tile.ks_background_color.split(',')[1], -10)); +// style_image_body_l2 = "background-color:" + ks_rgba_dark_background_color_l2 + ";"; + style_image_body_l2 = this._ksMainBodyStyle(ks_rgba_background_color, ks_rgba_font_color, tile).style_image_body_l2; + item_view = QWeb.render('ks_dashboard_item_layout2', { + item: tile, + style_image_body_l2: style_image_body_l2, + style_main_body: style_main_body, + ks_icon_url: ks_icon_url, + ks_rgba_default_icon_color: ks_rgba_default_icon_color, + ks_rgba_button_color:ks_rgba_button_color, + ks_container_class: ks_container_class, + ks_inner_container_class: ks_inner_container_class, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + data_count: data_count, + count: count, + ks_info: ks_description, + + }); + break; + + case 'layout3': + item_view = QWeb.render('ks_dashboard_item_layout3', { + item: tile, + style_main_body: style_main_body, + ks_icon_url: ks_icon_url, + ks_rgba_default_icon_color: ks_rgba_default_icon_color, + ks_rgba_button_color:ks_rgba_button_color, + ks_container_class: ks_container_class, + ks_inner_container_class: ks_inner_container_class, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + data_count: data_count, + count: count, + ks_info: ks_description, + + }); + break; + + case 'layout4': + style_main_body = "color : " + ks_rgba_font_color + ";border : solid;border-width : 1px;" +// style_image_body_l2 = "background-color:" + ks_rgba_background_color + ";"; + style_image_body_l2 = this._ksMainBodyStyle(ks_rgba_background_color, ks_rgba_font_color, tile).background_style; + style_domain_count_body = "color:" + ks_rgba_background_color + ";"; + item_view = QWeb.render('ks_dashboard_item_layout4', { + item: tile, + style_main_body: style_main_body, + style_image_body_l2: style_image_body_l2, + style_domain_count_body: style_domain_count_body, + ks_icon_url: ks_icon_url, + ks_rgba_default_icon_color: ks_rgba_default_icon_color, + ks_rgba_button_color:ks_rgba_button_color, + ks_container_class: ks_container_class, + ks_inner_container_class: ks_inner_container_class, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + data_count: data_count, + count: count, + ks_info: ks_description, + + }); + break; + + case 'layout5': + item_view = QWeb.render('ks_dashboard_item_layout5', { + item: tile, + style_main_body: style_main_body, + ks_icon_url: ks_icon_url, + ks_rgba_default_icon_color: ks_rgba_default_icon_color, + ks_rgba_button_color:ks_rgba_button_color, + ks_container_class: ks_container_class, + ks_inner_container_class: ks_inner_container_class, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + data_count: data_count, + count: count, + ks_info: ks_description, + + }); + break; + + case 'layout6': + ks_rgba_default_icon_color = self._ks_get_rgba_format(tile.ks_default_icon_color); + item_view = QWeb.render('ks_dashboard_item_layout6', { + item: tile, + style_image_body_l2: style_image_body_l2, + style_main_body: style_main_body, + ks_icon_url: ks_icon_url, + ks_rgba_default_icon_color: ks_rgba_default_icon_color, + ks_rgba_button_color:ks_rgba_button_color, + ks_container_class: ks_container_class, + ks_inner_container_class: ks_inner_container_class, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + data_count: data_count, + count: count, + ks_info: ks_description, + + }); + break; + + default: + item_view = QWeb.render('ks_dashboard_item_layout_default', { + item: tile + }); + break; + } + + + return item_view + }, + + ks_container_option: function(chart_title, ksIsDashboardManager, ksIsUser, ks_dashboard_list, chart_id, chart_family, chart_type, ksChartColorOptions, ks_info, ks_company,ks_dashboard_item_type){ + var container_data = { + ks_chart_title: chart_title, + ksIsDashboardManager: ksIsDashboardManager, + ksIsUser:ksIsUser, + ks_dashboard_list: ks_dashboard_list, + chart_id: chart_id, + chart_family: chart_family, + chart_type: chart_type, + ksChartColorOptions: ksChartColorOptions, + ks_info:ks_info, + ks_company:ks_company, + ks_dashboard_item_type:ks_dashboard_item_type + } + return container_data; + }, + + ks_set_selected_color_pallet: function($ks_gridstack_container, item){ + $ks_gridstack_container.find('.ks_li_' + item.ks_chart_item_color).addClass('ks_date_filter_selected'); + }, + + _renderGraph: function(item) { + var self = this; + var chart_data = JSON.parse(item.ks_chart_data); + var isDrill = item.isDrill ? item.isDrill : false; + var chart_id = item.id, + chart_title = item.name; + var chart_title = item.name; + var chart_type = item.ks_dashboard_item_type.split('_')[1]; + switch (chart_type) { + case "pie": + case "doughnut": + case "polarArea": + var chart_family = "circle"; + break; + case "radar": + var chart_family = "circle"; + break; + case "bar": + case "horizontalBar": + case "line": + case "area": + var chart_family = "square" + break; + case "scatter": + + var chart_family = "square" + break; + default: + var chart_family = "none"; + break; + + } + if (item.ks_info){ + var ks_description = item.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + + var container_data = this.ks_container_option(chart_title, self.ks_dashboard_data.ks_dashboard_manager, true, self.ks_dashboard_data.ks_dashboard_list, chart_id, chart_family, chart_type, this.ksChartColorOptions, ks_description, item.ks_company, item.ks_dashboard_item_type); + + var $ks_gridstack_container = $(QWeb.render('ks_gridstack_container', container_data)).addClass('ks_dashboarditem_id'); + self.ks_set_selected_color_pallet($ks_gridstack_container, item); +// $ks_gridstack_container.find('.ks_li_' + item.ks_chart_item_color).addClass('ks_date_filter_selected'); + + var ksLayoutGridId = $(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id') + if(ksLayoutGridId && ksLayoutGridId != 'ks_default'){ + self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_child_boards[parseInt(ksLayoutGridId)][1]) + } + parseInt($(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id')) + if (chart_id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:true,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } + else{ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:false,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } +// self.grid.addWidget($ks_gridstack_container, self.gridstackConfig[chart_id].x, self.gridstackConfig[chart_id].y, self.gridstackConfig[chart_id].width, self.gridstackConfig[chart_id].height, false, 11, null, 3, null, chart_id); + } else { +// self.grid.addWidget($ks_gridstack_container, 0, 0, 13, 4, true, 11, null, 3, null, chart_id); + self.grid.addWidget($ks_gridstack_container[0], {x:0, y:0, w:5, h:4,autoPosition:true,minW:4,maxW:null,minH:3,maxH:null, id :chart_id}); + } + self._renderChart($ks_gridstack_container, item); + }, + + ks_chart_color_pallet: function(gradient, setsCount, palette, item){ + var chartColors = []; + var color_set = ['#F04F65', '#f69032', '#fdc233', '#53cfce', '#36a2ec', '#8a79fd', '#b1b5be', '#1c425c', '#8c2620', '#71ecef', '#0b4295', '#f2e6ce', '#1379e7'] + if (palette !== "default") { + //Get a sorted array of the gradient keys + var gradientKeys = Object.keys(gradient); + gradientKeys.sort(function(a, b) { + return +a - +b; + }); + for (var i = 0; i < setsCount; i++) { + var gradientIndex = (i + 1) * (100 / (setsCount + 1)); //Find where to get a color from the gradient + for (var j = 0; j < gradientKeys.length; j++) { + var gradientKey = gradientKeys[j]; + if (gradientIndex === +gradientKey) { //Exact match with a gradient key - just get that color + chartColors[i] = 'rgba(' + gradient[gradientKey].toString() + ')'; + break; + } else if (gradientIndex < +gradientKey) { //It's somewhere between this gradient key and the previous + var prevKey = gradientKeys[j - 1]; + var gradientPartIndex = (gradientIndex - prevKey) / (gradientKey - prevKey); //Calculate where + var color = []; + for (var k = 0; k < 4; k++) { //Loop through Red, Green, Blue and Alpha and calculate the correct color and opacity + color[k] = gradient[prevKey][k] - ((gradient[prevKey][k] - gradient[gradientKey][k]) * gradientPartIndex); + if (k < 3) color[k] = Math.round(color[k]); + } + chartColors[i] = 'rgba(' + color.toString() + ')'; + break; + } + } + } + } else { + for (var i = 0, counter = 0; i < setsCount; i++, counter++) { + if (counter >= color_set.length) counter = 0; // reset back to the beginning + + chartColors.push(color_set[counter]); + } + + } + return chartColors; + }, + + _renderChart: function($ks_gridstack_container, item) { + var self = this; + var chart_data = JSON.parse(item.ks_chart_data); + if (item.ks_chart_cumulative_field.length > 0){ + + for (var i=0; i< chart_data.datasets.length; i++){ + var ks_temp_com = 0 + var data = [] + var datasets = {} + if (chart_data.datasets[i].ks_chart_cumulative_field){ + for (var j=0; j < chart_data.datasets[i].data.length; j++) + { + ks_temp_com = ks_temp_com + chart_data.datasets[i].data[j]; + data.push(ks_temp_com); + } + datasets.label = 'Cumulative' + chart_data.datasets[i].label; + datasets.data = data; + if (item.ks_chart_cumulative){ + datasets.type = 'line'; + } + chart_data.datasets.push(datasets); + } + } + } + if (item.ks_as_of_now){ + for (var i=0; i< chart_data.datasets.length; i++){ + if (chart_data.datasets[i].ks_as_of_now){ + var ks_temp_com = 0 + var data = [] + var datasets = {} + for (var j=0; j < chart_data.datasets[i].data.length; j++) + { + ks_temp_com = ks_temp_com + chart_data.datasets[i].data[j]; + data.push(ks_temp_com); + } + chart_data.datasets[i].data = data.slice(-item.ks_record_data_limit) + } else{ + chart_data.datasets[i].data = chart_data.datasets[i].data.slice(-item.ks_record_data_limit) + } + } + + chart_data['labels'] = chart_data['labels'].slice(-item.ks_record_data_limit) + + } + if (item.ks_chart_is_cumulative && item.ks_chart_data_count_type == 'count' && item.ks_dashboard_item_type === 'ks_bar_chart' && chart_data.datasets[0] && chart_data.datasets[0].data && item.ks_chart_data_count_type !== 'ks_scatter_chart'){ + var ks_temp_com = 0 + var data = [] + var datasets = {} + for (var j=0; j < chart_data.datasets[0].data.length; j++){ + ks_temp_com = ks_temp_com + chart_data.datasets[0].data[j]; + data.push(ks_temp_com); + } + datasets.label = 'Cumulative' + chart_data.datasets[0].label; + datasets.data = data; + if (item.ks_chart_cumulative){ + datasets.type = 'line'; + } + chart_data.datasets.push(datasets); + } + var isDrill = item.isDrill ? item.isDrill : false; + var chart_id = item.id, + chart_title = item.name; + var chart_title = item.name; + var chart_type = item.ks_dashboard_item_type.split('_')[1]; + switch (chart_type) { + case "pie": + case "doughnut": + case "polarArea": + var chart_family = "circle"; + break; + case "radar": + var chart_family = "circle"; + break; + case "bar": + case "horizontalBar": + case "line": + case "area": + var chart_family = "square" + break; + case "scatter": + + var chart_family = "square" + break; + default: + var chart_family = "none"; + break; + + } + $ks_gridstack_container.find('.ks_color_pallate').data({ + chartType: chart_type, + chartFamily: chart_family + }); { + chartType: "pie" + } + var $ksChartContainer = $(''); + $ks_gridstack_container.find('.card-body').append($ksChartContainer); + if (!item.ks_show_records) { + $ks_gridstack_container.find('.ks_dashboard_item_chart_info').hide(); + } + item.$el = $ks_gridstack_container; + if (chart_family === "circle") { + if (chart_data && chart_data['labels'].length > 30) { + $ks_gridstack_container.find(".ks_dashboard_color_option").remove(); + $ks_gridstack_container.find(".card-body").empty().append($("
Too many records for selected Chart Type. Consider using Domain to filter records or Record Limit to limit the no of records under 30.")); + return; + } + } + + if (chart_data["ks_show_second_y_scale"] && item.ks_dashboard_item_type === 'ks_bar_chart') { + var scales = {} + scales.yAxes = [{ + type: "linear", + display: true, + position: "left", + id: "y-axis-0", + gridLines: { + display: true + }, + labels: { + show: true, + } + }, + { + type: "linear", + display: true, + position: "right", + id: "y-axis-1", + labels: { + show: true, + }, + ticks: { + beginAtZero: true, + callback: function(value, index, values) { + var ks_selection = chart_data.ks_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = chart_data.ks_currency; + var ks_data = value; + ks_data = KsGlobalFunction._onKsGlobalFormatter(ks_data, item.ks_data_formatting, item.ks_precision_digits); + ks_data = KsGlobalFunction.ks_monetary(ks_data, ks_currency_id); + return ks_data; + } else if (ks_selection === 'custom') { + var ks_field = chart_data.ks_field; + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits) + ' ' + ks_field; + + } else { + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits); + } + }, + } + } + ] + } + var chart_plugin = []; + if (item.ks_show_data_value) { + chart_plugin.push(ChartDataLabels); + } + if (item.ks_dashboard_item_type =="ks_scatter_chart"){ + var scatter_data = [] + for (let i = 0 ; i 0){ +//// for(let i=0;i { + sum += data; + }); + let percentage = sum === 0 ? 0 + "%" : (value * 100 / sum).toFixed(2) + "%"; + if (item.ks_data_label_type == 'value'){ + percentage = value; + var ks_selection = chart_data.ks_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = chart_data.ks_currency; + var ks_data = value; + ks_data = KsGlobalFunction._onKsGlobalFormatter(ks_data, item.ks_data_formatting, item.ks_precision_digits); + ks_data = KsGlobalFunction.ks_monetary(ks_data, ks_currency_id); + percentage = ks_data; + } else if (ks_selection === 'custom') { + var ks_field = chart_data.ks_field; + percentage = KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits) + ' ' + ks_field; + + } else { + percentage = KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits); + } + } + return percentage; + }, + }, + }, + + } + }); + + this.chart_container[chart_id] = ksMyChart; + if (chart_data && chart_data["datasets"].length > 0) self.ksChartColors(item.ks_chart_item_color, ksMyChart, chart_type, chart_family, item.ks_bar_chart_stacked, item.ks_semi_circle_chart, item.ks_show_data_value, chart_data, item); + + }, + + ksHideFunction: function(options, item, ksChartFamily, chartType) { + return options; + }, + + ksChartColors: function(palette, ksMyChart, ksChartType, ksChartFamily, stack, semi_circle, ks_show_data_value, chart_data, item) { + var self = this; + var currentPalette = "cool"; + if (!palette) palette = currentPalette; + currentPalette = palette; + + /*Gradients + The keys are percentage and the values are the color in a rgba format. + You can have as many "color stops" (%) as you like. + 0% and 100% is not optional.*/ + var gradient; + switch (palette) { + case 'cool': + gradient = { + 0: [255, 255, 255, 1], + 20: [220, 237, 200, 1], + 45: [66, 179, 213, 1], + 65: [26, 39, 62, 1], + 100: [0, 0, 0, 1] + }; + break; + case 'warm': + gradient = { + 0: [255, 255, 255, 1], + 20: [254, 235, 101, 1], + 45: [228, 82, 27, 1], + 65: [77, 52, 47, 1], + 100: [0, 0, 0, 1] + }; + break; + case 'neon': + gradient = { + 0: [255, 255, 255, 1], + 20: [255, 236, 179, 1], + 45: [232, 82, 133, 1], + 65: [106, 27, 154, 1], + 100: [0, 0, 0, 1] + }; + break; + + case 'default': + var color_set = ['#F04F65', '#f69032', '#fdc233', '#53cfce', '#36a2ec', '#8a79fd', '#b1b5be', '#1c425c', '#8c2620', '#71ecef', '#0b4295', '#f2e6ce', '#1379e7'] + } + + //Find datasets and length + var chartType = ksMyChart.config.type; + switch (chartType) { + case "pie": + case "doughnut": + case "polarArea": + if (ksMyChart.config.data.datasets[0]){ + var datasets = ksMyChart.config.data.datasets[0]; + var setsCount = datasets.data.length; + } + break; + case "radar": + if (ksMyChart.config.data.datasets[0]){ + var datasets = ksMyChart.config.data.datasets[0]; + var setsCount = datasets.data.length; + } + break; + + case "bar": + case "horizontalBar": + case "line": + case "scatter": + + if (ksMyChart.config.data.datasets[0]){ + var datasets = ksMyChart.config.data.datasets; + var setsCount = datasets.length; + } + break; + } + + //Calculate colors +// var chartColors = []; +// +// if (palette !== "default") { +// //Get a sorted array of the gradient keys +// var gradientKeys = Object.keys(gradient); +// gradientKeys.sort(function(a, b) { +// return +a - +b; +// }); +// for (var i = 0; i < setsCount; i++) { +// var gradientIndex = (i + 1) * (100 / (setsCount + 1)); //Find where to get a color from the gradient +// for (var j = 0; j < gradientKeys.length; j++) { +// var gradientKey = gradientKeys[j]; +// if (gradientIndex === +gradientKey) { //Exact match with a gradient key - just get that color +// chartColors[i] = 'rgba(' + gradient[gradientKey].toString() + ')'; +// break; +// } else if (gradientIndex < +gradientKey) { //It's somewhere between this gradient key and the previous +// var prevKey = gradientKeys[j - 1]; +// var gradientPartIndex = (gradientIndex - prevKey) / (gradientKey - prevKey); //Calculate where +// var color = []; +// for (var k = 0; k < 4; k++) { //Loop through Red, Green, Blue and Alpha and calculate the correct color and opacity +// color[k] = gradient[prevKey][k] - ((gradient[prevKey][k] - gradient[gradientKey][k]) * gradientPartIndex); +// if (k < 3) color[k] = Math.round(color[k]); +// } +// chartColors[i] = 'rgba(' + color.toString() + ')'; +// break; +// } +// } +// } +// } else { +// for (var i = 0, counter = 0; i < setsCount; i++, counter++) { +// if (counter >= color_set.length) counter = 0; // reset back to the beginning +// +// chartColors.push(color_set[counter]); +// } +// } + var chartColors = this.ks_chart_color_pallet(gradient, setsCount, palette, item); + var datasets = ksMyChart.config.data.datasets; + var options = ksMyChart.config.options; + + options.legend.labels.usePointStyle = true; + if (ksChartFamily == "circle") { + if (ks_show_data_value) { + options.legend.position = 'bottom'; + options.layout.padding.top = 10; + options.layout.padding.bottom = 20; + options.layout.padding.left = 20; + options.layout.padding.right = 20; + } else { + options.legend.position = 'top'; + } + + options = self.ksHideFunction(options, item, ksChartFamily, chartType); + + options.plugins.datalabels.align = 'center'; + options.plugins.datalabels.anchor = 'end'; + options.plugins.datalabels.borderColor = 'white'; + options.plugins.datalabels.borderRadius = 25; + options.plugins.datalabels.borderWidth = 2; + options.plugins.datalabels.clamp = true; + options.plugins.datalabels.clip = false; + + options.tooltips.callbacks = { + title: function(tooltipItem, data) { + var ks_self = self; + var k_amount = data.datasets[tooltipItem[0].datasetIndex]['data'][tooltipItem[0].index]; + var ks_selection = chart_data.ks_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = chart_data.ks_currency; + k_amount = KsGlobalFunction.ks_monetary(k_amount, ks_currency_id); + return data.datasets[tooltipItem[0].datasetIndex]['label'] + " : " + k_amount + } else if (ks_selection === 'custom') { + var ks_field = chart_data.ks_field; + // ks_type = field_utils.format.char(ks_field); + k_amount = field_utils.format.float(k_amount, Float64Array, {digits:[0,item.ks_precision_digits]}); + return data.datasets[tooltipItem[0].datasetIndex]['label'] + " : " + k_amount + " " + ks_field; + } else { + k_amount = field_utils.format.float(k_amount, Float64Array, {digits:[0,item.ks_precision_digits]}); + return data.datasets[tooltipItem[0].datasetIndex]['label'] + " : " + k_amount + } + }, + label: function(tooltipItem, data) { + return data.labels[tooltipItem.index]; + }, + } + for (var i = 0; i < datasets.length; i++) { + if (chartType == "radar"){ + datasets[i].borderColor = chartColors[i]; + + datasets[i]['datalabels'] = { + backgroundColor: chartColors, + } + } else { + datasets[i].backgroundColor = chartColors; + datasets[i].borderColor = "rgba(255,255,255,1)"; + } + + switch (ksChartType) { + case "radar": + datasets[i].borderColor = chartColors[i]; + break; + } + } + if (semi_circle && (chartType === "pie" || chartType === "doughnut")) { + options.rotation = 1 * Math.PI; + options.circumference = 1 * Math.PI; + } + } else if (ksChartFamily == "square") { + options = self.ksHideFunction(options, item, ksChartFamily, chartType); + + options.scales.xAxes[0].gridLines.display = false; + options.scales.yAxes[0].ticks.beginAtZero = true; + + options.plugins.datalabels.align = 'end'; + + options.plugins.datalabels.formatter = function(value, ctx) { + var ks_selection = chart_data.ks_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = chart_data.ks_currency; + var ks_data = value; + ks_data = KsGlobalFunction._onKsGlobalFormatter(ks_data, item.ks_data_formatting, item.ks_precision_digits); + ks_data = KsGlobalFunction.ks_monetary(ks_data, ks_currency_id); + return ks_data; + } else if (ks_selection === 'custom') { + var ks_field = chart_data.ks_field; + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits) + ' ' + ks_field; + + } else { + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits); + } + }; + + if (chartType === "line") { + options.plugins.datalabels.backgroundColor = function(context) { + return context.dataset.borderColor; + }; + } + + if (chartType === "horizontalBar") { + options.scales.xAxes[0].ticks.callback = function(value, index, values) { + var ks_selection = chart_data.ks_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = chart_data.ks_currency; + var ks_data = value; + ks_data = KsGlobalFunction._onKsGlobalFormatter(ks_data, item.ks_data_formatting, item.ks_precision_digits); + ks_data = KsGlobalFunction.ks_monetary(ks_data, ks_currency_id); + return ks_data; + } else if (ks_selection === 'custom') { + var ks_field = chart_data.ks_field; + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits) + ' ' + ks_field; + + } else { + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits); + } + } + options.scales.xAxes[0].ticks.beginAtZero = true; + } else { + options.scales.yAxes[0].ticks.callback = function(value, index, values) { + var ks_selection = chart_data.ks_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = chart_data.ks_currency; + var ks_data = value; + ks_data = KsGlobalFunction._onKsGlobalFormatter(ks_data, item.ks_data_formatting, item.ks_precision_digits); + ks_data = KsGlobalFunction.ks_monetary(ks_data, ks_currency_id); + return ks_data; + } else if (ks_selection === 'custom') { + var ks_field = chart_data.ks_field; + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits) + ' ' + ks_field; + + } else { + return KsGlobalFunction._onKsGlobalFormatter(value, item.ks_data_formatting, item.ks_precision_digits); + } + } + } + if (this.chart_type !== 'scatter'){ + options.tooltips.callbacks = { + label: function(tooltipItem, data) { + var ks_self = self; + var k_amount = data.datasets[tooltipItem.datasetIndex]['data'][tooltipItem.index]; + var ks_selection = chart_data.ks_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = chart_data.ks_currency; + k_amount = KsGlobalFunction.ks_monetary(k_amount, ks_currency_id); + return data.datasets[tooltipItem.datasetIndex]['label'] + " : " + k_amount + } else if (ks_selection === 'custom') { + var ks_field = chart_data.ks_field; + // ks_type = field_utils.format.char(ks_field); + k_amount = field_utils.format.float(k_amount, Float64Array, {digits:[0,item.ks_precision_digits]}); + return data.datasets[tooltipItem.datasetIndex]['label'] + " : " + k_amount + " " + ks_field; + } else { + k_amount = field_utils.format.float(k_amount, Float64Array,{digits:[0,item.ks_precision_digits]}); + return data.datasets[tooltipItem.datasetIndex]['label'] + " : " + k_amount + } + } + } + } + + for (var i = 0; i < datasets.length; i++) { + switch (ksChartType) { + case "bar": + case "horizontalBar": + if (datasets[i].type && datasets[i].type == "line") { + datasets[i].borderColor = chartColors[i]; + datasets[i].backgroundColor = "rgba(255,255,255,0)"; + datasets[i]['datalabels'] = { + backgroundColor: chartColors[i], + } + } else { + datasets[i].backgroundColor = chartColors[i]; + datasets[i].borderColor = "rgba(255,255,255,0)"; + options.scales.xAxes[0].stacked = stack; + options.scales.yAxes[0].stacked = stack; + } + break; + case "scatter": + datasets[i].backgroundColor = chartColors[i]; + datasets[i]['datalabels'] = { + backgroundColor: chartColors[i], + } + break; + case "line": + datasets[i].borderColor = chartColors[i]; + datasets[i].backgroundColor = "rgba(255,255,255,0)"; + break; + case "area": + datasets[i].borderColor = chartColors[i]; + break; + } + } + + } + ksMyChart.update(); + }, + + onChartCanvasClick: function(evt) { + + var self = this; +// $(self.$el.find('.ks_pager')).addClass('d-none'); + if (evt.currentTarget.classList.value !== 'ks_list_canvas_click') { + var item_id = evt.currentTarget.dataset.chartId; + if (item_id in self.ksUpdateDashboard) { + clearInterval(self.ksUpdateDashboard[item_id]); + delete self.ksUpdateDashboard[item_id] + } + var myChart = self.chart_container[item_id]; + var activePoint = myChart.getElementAtEvent(evt)[0]; + if (activePoint) { + var item_data = self.ks_dashboard_data.ks_item_data[item_id]; + var groupBy = JSON.parse(item_data["ks_chart_data"])['groupby']; + if (activePoint._chart.data.domains) { + var sequnce = item_data.sequnce ? item_data.sequnce : 0; + + var domain = activePoint._chart.data.domains[activePoint._index] + if (item_data.max_sequnce != 0 && sequnce < item_data.max_sequnce) { + self._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'ks_fetch_drill_down_data', + args: [item_id, domain, sequnce] + }).then(function(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) { + 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; + } + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").removeClass('d-sm-block '); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").addClass('d-none'); + + $(self.$el.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_flower_view'){ + self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove(); + self.ksrenderflowerchart(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]"),item_data); + }else if(item_data.ks_dashboard_item_type == 'ks_radialBar_chart'){ + self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove(); + self.ksrenderradialchart(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]"),item_data); + }else if(item_data.ks_dashboard_item_type == 'ks_bullet_chart'){ + self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove(); + self.ksrenderbulletchart(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]"),item_data); + }else if(item_data.ks_dashboard_item_type == 'ks_funnel_chart'){ + self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove(); + self.ksrenderfunnelchart(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]"),item_data); + }else{ + self._renderChart($(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]), item_data); + } + } 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; + } + 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.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none'); + + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").empty(); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").removeClass('d-sm-block '); + + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").addClass('d-none'); + var item_data = self.ks_dashboard_data.ks_item_data[item_id] + var $container = self.renderListViewData(item_data); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").append($container).addClass('ks_overflow'); + } + }); + } else { + if (item_data.action) { + if (!item_data.ks_is_client_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 = Object.assign({}, item_data.action[0]); + if (action.params){ + action.params.default_active_id || 'mailbox_inbox'; + }else{ + action.params = { + 'default_active_id': 'mailbox_inbox' + }; + action.context = {} + action.context.params = { + 'active_model': false + }; + } + } + } 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) { + + + if (item_data.ks_is_client_action){ + self.__parentedParent.actionService.doAction(action,{}) + }else{ + self.do_action(action, { + on_reverse_breadcrumb: self.on_reverse_breadcrumb, + }); + } + } + } + } + } + } else { + var item_id = $(evt.target).parent().data().itemId; + if (this.ksUpdateDashboard[item_id]) { + clearInterval(this.ksUpdateDashboard[item_id]); + delete self.ksUpdateDashboard[item_id]; + } + 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({ + model: 'ks_dashboard_ninja.item', + method: 'ks_fetch_drill_down_data', + args: [item_id, domain, sequence] + }).then(function(result) { + if (result.ks_list_view_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_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; + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").empty(); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_plus").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_minus").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_pager").addClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_action_export").addClass('d-none'); + $(self.$el.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 $container = self.renderListViewData(item_data); + $(self.$el.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; + 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; + } + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_plus").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_minus").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_pager").addClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").removeClass('d-sm-block '); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_action_export").addClass('d-none'); + $(self.$el.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] + self._renderChart($(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]), item_data); + } + }); + } + } + } + evt.stopPropagation(); + }, + + ksOnDrillUp: function(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; + if(item_data) { + + if ('domains' in item_data) { + domain = item_data['domains'][item_data.sequnce - 1] ? item_data['domains'][item_data.sequnce - 1] : [] + var sequnce = item_data.sequnce - 2; + if (sequnce >= 0) { + self._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'ks_fetch_drill_down_data', + args: [item_id, domain, sequnce] + }).then(function(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; + if (result.ks_chart_type) self.ks_dashboard_data.ks_item_data[item_id]['ks_dashboard_item_type'] = result.ks_chart_type; + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none'); + $(self.$el.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]; + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none') + self._renderChart($(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]), item_data); + + } 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'; + var item_data = self.ks_dashboard_data.ks_item_data[item_id] + var $container = self.renderListViewData(item_data); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_pager").addClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").addClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").append($container); + } + + }); + + } else { + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").addClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").addClass('d-sm-block '); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").removeClass('d-none'); + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_action_export").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_plus").removeClass('d-none') + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_minus").removeClass('d-none') + self.ksFetchChartItem(item_id) +// $(self.$el.find('.ks_pager')).removeClass('d-none'); + var updateValue = self.ks_dashboard_data.ks_set_interval; + if (updateValue) { + var updateinterval = setInterval(function() { + self.ksFetchChartItem(item_id) + }, updateValue); + self.ksUpdateDashboard[item_id] = updateinterval; + } + } + + } else { + if(!domain){ + $(self.$el.find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").addClass('d-none'); + } + + } + } + + e.stopPropagation(); + }, + + ksFetchChartItem: function(id) { + var self = this; + var item_data = self.ks_dashboard_data.ks_item_data[id]; + + return self._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'ks_fetch_item', + args: [ + [item_data.id], self.ks_dashboard_id, self.ksGetParamsForItemFetch(id) + ], + context: self.getContext(), + }).then(function(new_item_data) { + this.ks_dashboard_data.ks_item_data[id] = new_item_data[id]; + $(self.$el.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) { + var item_view = $(self.$el.find(".grid-stack-item[gs-id=" + id + "]").children()[0]); + var $container = self.renderListViewData(item_data); + item_view.find(".card-body").append($container); + var ks_length = JSON.parse(item_data['ks_list_view_data']).data_rows.length + if (new_item_data["ks_list_view_type"] === "ungrouped" && JSON.parse(item_data['ks_list_view_data']).data_rows.length) { + item_view.find('.ks_pager').removeClass('d-none'); + if (item.ks_record_count <= item.ks_pagination_limit) item_view.find('.ks_load_next').addClass('ks_event_offer_list'); + item_view.find('.ks_value').text("1-" + JSON.parse(item_data['ks_list_view_data']).data_rows.length); + } else { + item_view.find('.ks_pager').addClass('d-none'); + } + }else if(item_data['ks_dashboard_item_type'] == 'ks_funnel_chart'){ + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrenderfunnelchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_bullet_chart'){ + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self. ksrenderbulletchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_flower_view'){ + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrenderflowerchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_radialBar_chart'){ + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrenderradialchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_map_view'){ + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrendermapview(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else { + self._renderChart($(self.$el.find(".grid-stack-item[gs-id=" + id + "]").children()[0]), item_data); + } + }.bind(this)); + }, + + onChartMoreInfoClick: function(evt) { + var self = this; + var item_id = evt.currentTarget.dataset.itemId; + var item_data = self.ks_dashboard_data.ks_item_data[item_id]; + var groupBy = item_data.ks_chart_groupby_type === 'relational_type' ? item_data.ks_chart_relation_groupby_name : item_data.ks_chart_relation_groupby_name + ':' + item_data.ks_chart_date_groupby; + var domain = JSON.parse(item_data.ks_chart_data).previous_domain + + if (item_data.ks_show_records) { + if (item_data.action) { + + if (!item_data.ks_is_client_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'] = item_data.ks_domain || []; + action['search_view_id'] = [action.search_view_id, 'search'] + }else{ + var action = Object.assign({}, item_data.action[0]); + if (action.params){ + action.params.default_active_id || 'mailbox_inbox'; + }else{ + action.params = { + 'default_active_id': 'mailbox_inbox' + } + action.context = {} + action.context.params = { + 'active_model': false + }; + } + } + } 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', + } + } + self.do_action(action, { + on_reverse_breadcrumb: self.on_reverse_breadcrumb, + }); + } + }, + + _ksRenderNoItemView: function() { + $('.ks_dashboard_items_list').remove(); + var self = this; + $(QWeb.render('ksNoItemView')).appendTo(self.$el) + + }, + + _ksRenderEditMode: function() { + + var self = this; + self.ks_mode = 'edit'; + self.ks_remove_update_interval(); + + $('#ks_dashboard_title_input').val(self.ks_dashboard_data.name); + + $('.ks_am_element').addClass("ks_hide"); + $('.ks_em_element').removeClass("ks_hide"); + $('.ks_dashboard_print_pdf').addClass("ks_hide"); + + self.$el.find('.ks_item_click').addClass('ks_item_not_click').removeClass('ks_item_click'); + self.$el.find('.ks_dashboard_item').removeClass('ks_dashboard_item_header_hover'); + self.$el.find('.ks_dashboard_item_header').removeClass('ks_dashboard_item_header_hover'); + + self.$el.find('.ks_dashboard_item_l2').removeClass('ks_dashboard_item_header_hover'); + self.$el.find('.ks_dashboard_item_header_l2').removeClass('ks_dashboard_item_header_hover'); + + self.$el.find('.ks_dashboard_item_l5').removeClass('ks_dashboard_item_header_hover'); + + self.$el.find('.ks_dashboard_item_button_container').removeClass('ks_dashboard_item_header_hover'); + + self.$el.find('.ks_dashboard_link').addClass("ks_hide") + self.$el.find('.ks_dashboard_top_settings').addClass("ks_hide") + self.$el.find('.ks_dashboard_edit_mode_settings').removeClass("ks_hide") + + // Adding Chart grab able cals + self.$el.find('.ks_start_tv_dashboard').addClass('ks_hide'); + self.$el.find('.ks_chart_container').addClass('ks_item_not_click'); + self.$el.find('.ks_list_view_container').addClass('ks_item_not_click'); + + if (self.grid) { + self.grid.enable(); + } + }, + + + _ksRenderActiveMode: function() { + var self = this + self.ks_mode = 'active'; + + if (self.grid && $('.grid-stack').data('gridstack')) { + $('.grid-stack').data('gridstack').disable(); + } + + if (self.ks_dashboard_data.ks_child_boards) { +// var dash_name = $('ul[id="ks_dashboard_layout_dropdown_container"] li[class="ks_dashboard_layout_event ks_layout_selected"] span').text() + var $layout_container = $(QWeb.render('ks_dn_layout_container', { + ks_selected_board_id: self.ks_dashboard_data.ks_selected_board_id, + ks_child_boards: self.ks_dashboard_data.ks_child_boards, + ks_multi_layout: self.ks_dashboard_data.multi_layouts, + ks_dash_name: self.ks_dashboard_data.name + })); + $('#ks_dashboard_title .ks_am_element').replaceWith($layout_container); + $('#ks_dashboard_title_label').replaceWith($layout_container); + } else { + $('#ks_dashboard_title_label').text(self.ks_dashboard_data.name); + } + + $('#ks_dashboard_title_label').text(self.ks_dashboard_data.name); + + $('.ks_am_element').removeClass("ks_hide"); + $('.ks_em_element').addClass("ks_hide"); + $('.ks_dashboard_print_pdf').removeClass("ks_hide"); + if (self.ks_dashboard_data.ks_item_data) $('.ks_am_content_element').removeClass("ks_hide"); + + self.$el.find('.ks_item_not_click').addClass('ks_item_click').removeClass('ks_item_not_click') + self.$el.find('.ks_dashboard_item').addClass('ks_dashboard_item_header_hover') + self.$el.find('.ks_dashboard_item_header').addClass('ks_dashboard_item_header_hover') + + self.$el.find('.ks_dashboard_item_l2').addClass('ks_dashboard_item_header_hover') + self.$el.find('.ks_dashboard_item_header_l2').addClass('ks_dashboard_item_header_hover') + + // For layout 5 + self.$el.find('.ks_dashboard_item_l5').addClass('ks_dashboard_item_header_hover') + + + self.$el.find('.ks_dashboard_item_button_container').addClass('ks_dashboard_item_header_hover'); + + self.$el.find('.ks_dashboard_top_settings').removeClass("ks_hide") + self.$el.find('.ks_dashboard_edit_mode_settings').addClass("ks_hide") + + self.$el.find('.ks_start_tv_dashboard').removeClass('ks_hide'); + self.$el.find('.ks_chart_container').removeClass('ks_item_not_click ks_item_click'); + self.$el.find('.ks_list_view_container').removeClass('ks_item_click'); + + self.ks_set_update_interval(); + self.grid.commit(); + }, + + _ksToggleEditMode: function() { + var self = this + if (self.ksDashboardEditMode) { + self._ksRenderActiveMode() + self.ksDashboardEditMode = false + } else if (!self.ksDashboardEditMode) { + self._ksRenderEditMode() + self.ksDashboardEditMode = true + } + + }, + + onAddItemTypeClick: function(e) { + var self = this; + if (e.currentTarget.dataset.item !== "ks_json") { + self.do_action({ + type: 'ir.actions.act_window', + res_model: 'ks_dashboard_ninja.item', + view_id: 'ks_dashboard_ninja_list_form_view', + views: [ + [false, 'form'] + ], + target: 'current', + context: { + 'ks_dashboard_id': self.ks_dashboard_id, + 'ks_dashboard_item_type': e.currentTarget.dataset.item, + '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, + }, + }, { + on_reverse_breadcrumb: this.on_reverse_breadcrumb, + }); + } else { + self.ksImportItemJson(e); + } + }, + + ksImportItemJson: function(e) { + var self = this; + $('.ks_input_import_item_button').click(); + }, + + ksImportItem: function(e) { + var self = this; + var fileReader = new FileReader(); + fileReader.onload = function() { + $('.ks_input_import_item_button').val(''); +// framework.blockUI(); + self._rpc({ + 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") { + + $.when(self.ks_fetch_data()).then(function() { + $.when(self.ks_fetch_items_data()).then(function(result){ + self.ksRenderDashboard(); + }); + +// framework.unblockUI(); + }); + } + }); + }; + fileReader.readAsText($('.ks_input_import_item_button').prop('files')[0]); + }, + + _onKsAddLayoutClick: function() { + var self = this; + + self.do_action({ + type: 'ir.actions.act_window', + res_model: 'ks_dashboard_ninja.item', + view_id: 'ks_dashboard_ninja_list_form_view', + views: [ + [false, 'form'] + ], + target: 'current', + context: { + 'ks_dashboard_id': self.ks_dashboard_id, + 'form_view_ref': 'ks_dashboard_ninja.item_form_view', + 'form_view_initial_mode': 'edit', + }, + }, { + on_reverse_breadcrumb: this.on_reverse_breadcrumb, + }); + }, + + _onKsEditLayoutClick: function() { + var self = this; + self.grid.setStatic(false); + self._ksRenderEditMode(); + }, + + _onKsSaveLayoutClick: function() { + this.grid.setStatic(true) + var self = this; + // Have to save dashboard here + var dashboard_title = $('#ks_dashboard_title_input').val(); + if (dashboard_title != false && dashboard_title != 0 && dashboard_title !== self.ks_dashboard_data.name) { + self.ks_dashboard_data.name = dashboard_title; + var model = 'ks_dashboard_ninja.board'; + var rec_id = self.ks_dashboard_id; + + 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][0] = dashboard_title; + if (this.ks_dashboard_data.ks_selected_board_id !== 'ks_default'){ + model = 'ks_dashboard_ninja.child_board'; + rec_id = this.ks_dashboard_data.ks_selected_board_id; + } + } + this._rpc({ + model: model, + method: 'write', + args: [rec_id, { + 'name': dashboard_title + }], + }) + } + if (this.ks_dashboard_data.ks_item_data) self._ksSaveCurrentLayout(); + self._ksRenderActiveMode(); + }, + + _onKsCreateLayoutClick: function() { + var self = this; + self.grid.setStatic(true) + var dashboard_title = $('#ks_dashboard_title_input').val(); + if (dashboard_title ==="") { + self.call('notification', 'notify', { + message: "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; + + var grid_config = self.ks_get_current_gridstack_config(); + this._rpc({ + 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, + }], + }).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: function(dashboard_title, res_id, grid_config){ + var self = this; + var child_board_id = res_id.toString(); + self.ks_dashboard_data.ks_selected_board_id = child_board_id; + var update_data = {}; + update_data[child_board_id] = [dashboard_title, JSON.stringify(grid_config)]; + self.ks_dashboard_data.ks_child_boards = _.extend(update_data,self.ks_dashboard_data.ks_child_boards); + }, + + _onKsCancelLayoutClick: function() { + var self = this; + // render page again + $.when(self.ks_fetch_data()).then(function() { + $.when(self.ks_fetch_items_data()).then(function(result){ + self.ksRenderDashboard(); + self.ks_set_update_interval(); + }); + }); + }, + + _onKsItemClick: function(e) { + var self = this; + // To Handle only allow item to open when not clicking on item + if (self.ksAllowItemClick) { + + + + e.preventDefault(); + if (e.target.title != "Customize Item") { + var item_id = parseInt(e.currentTarget.firstElementChild.id); + var item_data = self.ks_dashboard_data.ks_item_data[item_id]; + if (item_data && item_data.ks_show_records) { + + if (item_data.action) { + if (!item_data.ks_is_client_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'] = item_data.ks_domain || []; + action['search_view_id'] = [action.search_view_id, 'search'] + }else{ + var action = Object.assign({}, item_data.action[0]); + if (action.params){ + action.params.default_active_id || 'mailbox_inbox'; + }else{ + action.params = { + 'default_active_id': 'mailbox_inbox' + } + action.context = {} + action.context.params = { + 'active_model': false + }; + } + } + + } else { + var 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 (item_data.ks_is_client_action){ + self.__parentedParent.actionService.doAction(action,{}) + }else{ + self.do_action(action, { + on_reverse_breadcrumb: self.on_reverse_breadcrumb, + }); + } + } + } + } else { + self.ksAllowItemClick = true; + } + }, + + _onKsItemCustomizeClick: function(e) { + var self = this; + var id = parseInt($($(e.currentTarget).parentsUntil('.grid-stack').slice(-1)[0]).attr('gs-id')); + self.ks_open_item_form_page(id); + + e.stopPropagation(); + }, + + ks_open_item_form_page: function(id) { + var self = this; + self.do_action({ + type: 'ir.actions.act_window', + res_model: 'ks_dashboard_ninja.item', + view_id: 'ks_dashboard_ninja_list_form_view', + views: [ + [false, 'form'] + ], + target: 'current', + context: { + 'form_view_ref': 'ks_dashboard_ninja.item_form_view', + 'form_view_initial_mode': 'edit', + }, + res_id: id + }, { + on_reverse_breadcrumb: this.on_reverse_breadcrumb, + }); + }, + + + // Note : this is exceptionally bind to this function. + ksUpdateDashboardItem: function(ids) { + var self = this; + for (var i = 0; i < ids.length; i++) { + + var item_data = self.ks_dashboard_data.ks_item_data[ids[i]] + if (item_data['ks_dashboard_item_type'] == 'ks_list_view') { + var item_view = self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"); + var name = item_data.name ?item_data.name : item_data.ks_model_display_name; + item_view.children().find('.ks_list_view_heading').prop('title', name); + item_view.children().find('.ks_list_view_heading').text(name); + item_view.find('.card-body').empty(); + item_view.find('.ks_dashboard_item_drill_up').addClass('d-none') + item_view.find('.ks_dashboard_item_action_export').removeClass('d-none') + item_view.find('.ks_dashboard_quick_edit_action_popup ').removeClass('d-none') + item_view.find('.card-body').append(self.renderListViewData(item_data)); + var rows = JSON.parse(item_data['ks_list_view_data']).data_rows; + var ks_length = rows ? rows.length : false; + if (ks_length) { + if (item_view.find('.ks_pager_name')) { + item_view.find('.ks_pager_name').empty(); + var $ks_pager_container = QWeb.render('ks_pager_template', { + item_id: ids[i], + intial_count: item_data.ks_pagination_limit, + offset : 1 + }) + item_view.find('.ks_pager_name').append($($ks_pager_container)); + } + + if (ks_length < item_data.ks_pagination_limit) item_view.find('.ks_load_next').addClass('ks_event_offer_list'); + item_view.find('.ks_value').text("1-" + JSON.parse(item_data['ks_list_view_data']).data_rows.length); + + if (item_data.ks_record_data_limit == item_data.ks_pagination_limit || item_data.ks_record_count==item_data.ks_pagination_limit) { + item_view.find('.ks_load_next').addClass('ks_event_offer_list'); + } + } else { + item_view.find('.ks_pager').addClass('d-none'); + } + } else if (item_data['ks_dashboard_item_type'] == 'ks_tile') { + var item_view = self._ksRenderDashboardTile(item_data); + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".ks_dashboard_item_hover").replaceWith($(item_view).find('.ks_dashboarditem_id')); + } else if (item_data['ks_dashboard_item_type'] == 'ks_kpi') { + var item_view = self.renderKpi(item_data); + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".ks_dashboard_item_hover").replaceWith($(item_view).find('.ks_dashboarditem_id')); + } else if (item_data['ks_dashboard_item_type'] == 'ks_to_do'){ + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").empty(); + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").append(self.ksRenderToDoDashboardView(item_data)[0].children()); + }else if(item_data['ks_dashboard_item_type'] == 'ks_funnel_chart'){ + + if (item_data['ks_funnel_item_color']){ + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [item_data.id, { + "ks_funnel_item_color": item_data['ks_funnel_item_color'] + }], + }).then(function() { + item_data['ks_funnel_item_color'] = item_data['ks_funnel_item_color'] + }); + } + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrenderfunnelchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_bullet_chart'){ + + if (item_data['ks_funnel_item_color']){ + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [item_data.id, { + "ks_funnel_item_color": item_data['ks_funnel_item_color'] + }], + }).then(function() { + item_data['ks_funnel_item_color'] = item_data['ks_funnel_item_color'] + }); + } + + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self. ksrenderbulletchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_flower_view'){ + + if (item_data['ks_flower_item_color']){ + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [item_data.id, { + "ks_flower_item_color": item_data['ks_flower_item_color'] + }], + }).then(function() { + item_data['ks_flower_item_color'] = item_data['ks_flower_item_color'] + }); + } + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrenderflowerchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_radialBar_chart'){ + + if (item_data['ks_radial_item_color']){ + this._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [item_data.id, { + "ks_radial_item_color": item_data['ks_radial_item_color'] + }], + }).then(function() { + item_data['ks_radial_item_color'] = item_data['ks_radial_item_color'] + }); + } + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrenderradialchart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else if(item_data['ks_dashboard_item_type'] == 'ks_map_view'){ + self.$el.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; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self.ksrendermapview(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data); + }else{ + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").empty() + var name = item_data.name ?item_data.name : item_data.ks_model_display_name; + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name) + self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name) + self._renderChart(self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"), item_data); + } + + } + self.grid.setStatic(true); + }, + + _onKsDeleteItemClick: function(e) { + var self = this; + var item = $($(e.currentTarget).parentsUntil('.grid-stack').slice(-1)[0]) + var id = parseInt($($(e.currentTarget).parentsUntil('.grid-stack').slice(-1)[0]).attr('gs-id')); + self.ks_delete_item(id, item); + e.stopPropagation(); + }, + + ks_delete_item: function(id, item) { + var self = this; + Dialog.confirm(this, (_t("Are you sure you want to remove this item?")), { + confirm_callback: function() { + + self._rpc({ + model: 'ks_dashboard_ninja.item', + method: 'unlink', + args: [id], + }).then(function(result) { + + // Clean Item Remove Process. + self.ks_remove_update_interval(); + delete self.ks_dashboard_data.ks_item_data[id]; + self.grid.removeWidget(item); + self.ks_set_update_interval(); + + if (Object.keys(self.ks_dashboard_data.ks_item_data).length > 0) { + self._ksSaveCurrentLayout(); + } + else { + self._ksRenderNoItemView(); + self.ksRenderDashboard(); + } + $.when(self.ks_fetch_data()).then(function() { + $.when(self.ks_fetch_items_data()).then(function(){ + self.ks_remove_update_interval(); + self.ksRenderDashboard(); + self.ks_set_update_interval(); + }); + }); + }); + }, + }); + }, + ks_add_dashboard_item_on_empty: function(e){ + var self = this; + if (e.currentTarget.dataset.item !== "ks_json") { + self.do_action({ + type: 'ir.actions.act_window', + res_model: 'ks_dashboard_ninja.item', + view_id: 'ks_dashboard_ninja_list_form_view', + views: [ + [false, 'form'] + ], + target: 'current', + context: { + 'ks_dashboard_id': self.ks_dashboard_id, + 'form_view_ref': 'ks_dashboard_ninja.item_form_view', + 'form_view_initial_mode': 'edit', + }, + }, { + on_reverse_breadcrumb: this.on_reverse_breadcrumb, + }); + } else { + self.ksImportItemJson(e); + } + }, + + _ksSaveCurrentLayout: function() { + var self = this; + var grid_config = self.ks_get_current_gridstack_config(); + var model = 'ks_dashboard_ninja.child_board'; + var 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 = this.ks_dashboard_data.ks_selected_board_id; + } + } + if (!config.device.isMobile) { + this._rpc({ + model: model, + method: 'write', + args: [rec_id, { + "ks_gridstack_config": JSON.stringify(grid_config) + }], + }); + } + }, + + ks_get_current_gridstack_config: function(){ + var self = this; + if (document.querySelector('.grid-stack') && document.querySelector('.grid-stack').gridstack){ + var items = document.querySelector('.grid-stack').gridstack.el.gridstack.engine.nodes; + } + var grid_config = {} + +// if (self.ks_dashboard_data.ks_gridstack_config && config.device.isMobile) { +// _.extend(grid_config, JSON.parse(self.ks_dashboard_data.ks_gridstack_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; + }, + + _renderListView: function(item, grid) { + var self = this; + if (item.ks_info){ + var ks_description = item.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + + var list_view_data = JSON.parse(item.ks_list_view_data), + pager = true, + item_id = item.id, + data_rows = list_view_data.data_rows, + length = data_rows ? data_rows.length: false, + item_title = item.name, + ks_info = ks_description; + var $ksItemContainer = self.renderListViewData(item); + var ks_data_calculation_type = self.ks_dashboard_data.ks_item_data[item_id].ks_data_calculation_type + var $ks_gridstack_container = $(QWeb.render('ks_gridstack_list_view_container', { + ks_chart_title: item_title, + ksIsDashboardManager: self.ks_dashboard_data.ks_dashboard_manager, + ksIsUser: true, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + item_id: item_id, + count: '1-' + length, + offset: 1, + intial_count: length, + ks_pager: pager, + calculation_type: ks_data_calculation_type, + ks_info: ks_info, + ks_company:item.ks_company + + })).addClass('ks_dashboarditem_id'); + + if (item.ks_pagination_limit < length ) { + $ks_gridstack_container.find('.ks_load_next').addClass('ks_event_offer_list'); + } + if (length < item.ks_pagination_limit ) { + $ks_gridstack_container.find('.ks_load_next').addClass('ks_event_offer_list'); + } + if (item.ks_record_data_limit === item.ks_pagination_limit){ + $ks_gridstack_container.find('.ks_load_next').addClass('ks_event_offer_list'); + } + if (length == 0){ + $ks_gridstack_container.find('.ks_pager').addClass('d-none'); + } + if (item.ks_pagination_limit==0){ + $ks_gridstack_container.find('.ks_pager_name').addClass('d-none'); + } + + $ks_gridstack_container.find('.card-body').append($ksItemContainer); + if (item.ks_data_calculation_type === 'query' || item.ks_list_view_type === "ungrouped"){ + $ks_gridstack_container.find('.ks_list_canvas_click').removeClass('ks_list_canvas_click'); + } + item.$el = $ks_gridstack_container; + if (item_id in self.gridstackConfig) { + if (config.device.isMobile){ + grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[item_id].x, y:self.gridstackConfig[item_id].y, w:self.gridstackConfig[item_id].w, h:self.gridstackConfig[item_id].h, autoPosition:true, minW:3, maxW:null, minH:3, maxH:null, id:item_id}); + } + else{ + grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[item_id].x, y:self.gridstackConfig[item_id].y, w:self.gridstackConfig[item_id].w, h:self.gridstackConfig[item_id].h, autoPosition:false, minW:3, maxW:null, minH:3, maxH:null, id:item_id}); + } + } else { + grid.addWidget($ks_gridstack_container[0], {x:0, y:0, w:5, h:4, autoPosition:true, minW:4, maxW:null, minH:3, maxH:null, id:item_id}); + } + }, + + renderListViewData: function(item) { + var self = this; + var list_view_data = JSON.parse(item.ks_list_view_data); + var item_id = item.id, + data_rows = list_view_data.data_rows, + item_title = item.name; + if (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'){ + list_view_data.data_rows[j]["data"][index] = moment(new Date(date)).format(this.date_format) , {}, {timezone: false}; + }else{ + list_view_data.data_rows[j]["data"][index] = moment(new Date(date+" UTC")).format(this.datetime_format), {}, {timezone: false}; + } + }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] = field_utils.format.float(list_view_data.data_rows[i].data[j], Float64Array, {digits:[0,item.ks_precision_digits]}) + } + } else { + list_view_data.data_rows[i].data[j] = ""; + } + } + } + } + var $ksItemContainer = $(QWeb.render('ks_list_view_table', { + list_view_data: list_view_data, + item_id: item_id, + list_type: item.ks_list_view_type, + isDrill: self.ks_dashboard_data.ks_item_data[item_id]['isDrill'] + })); + self.list_container = $ksItemContainer; + if (list_view_data){ + var $ksitemBody = self.ksListViewBody(list_view_data,item_id) + self.list_container.find('.ks_table_body').append($ksitemBody) + } + if (item.ks_list_view_type === "ungrouped") { + $ksItemContainer.find('.ks_list_canvas_click').removeClass('ks_list_canvas_click'); + } + + if (!item.ks_show_records) { + $ksItemContainer.find('#ks_item_info').hide(); + } + return $ksItemContainer + }, + + ksListViewBody: function(list_view_data, item_id) { + var self = this; + var itemid = item_id + var ks_data_calculation_type = self.ks_dashboard_data.ks_item_data[item_id].ks_data_calculation_type; + var list_view_type = self.ks_dashboard_data.ks_item_data[item_id].ks_list_view_type + var $ksitemBody = $(QWeb.render('ks_list_view_tmpl', { + list_view_data: list_view_data, + item_id: itemid, + calculation_type: ks_data_calculation_type, + isDrill: self.ks_dashboard_data.ks_item_data[item_id]['isDrill'], + list_type: list_view_type, + })); + return $ksitemBody; + + }, + + ksSum: function(count_1, count_2, item_info, field, target_1, $kpi_preview, kpi_data) { + var self = this; + var count = count_1 + count_2; + if (field.ks_multiplier_active){ + item_info['count'] = KsGlobalFunction._onKsGlobalFormatter(count* field.ks_multiplier, field.ks_data_formatting, field.ks_precision_digits); + item_info['count_tooltip'] = field_utils.format.float(count * field.ks_multiplier, Float64Array, {digits:[0,field.ks_precision_digits]}); + }else{ + + item_info['count'] = KsGlobalFunction._onKsGlobalFormatter(count, field.ks_data_formatting, field.ks_precision_digits); + item_info['count_tooltip'] = field_utils.format.float(parseFloat(count), Float64Array, {digits:[0,field.ks_precision_digits]}); + } + if (field.ks_multiplier_active){ + count = count * field.ks_multiplier; + } + item_info['target_enable'] = field.ks_goal_enable; + var ks_color = (target_1 - count) > 0 ? "red" : "green"; + item_info.pre_arrow = (target_1 - count) > 0 ? "down" : "up"; + item_info['ks_comparison'] = true; + var target_deviation = (target_1 - count) > 0 ? Math.round(((target_1 - count) / target_1) * 100) : Math.round((Math.abs((target_1 - count)) / target_1) * 100); + if (target_deviation !== Infinity) item_info.target_deviation = field_utils.format.integer(target_deviation) + "%"; + else { + item_info.target_deviation = 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 = field_utils.format.integer(target_progress_deviation) + "%"; + $kpi_preview = $(QWeb.render("ks_kpi_template_2", item_info)); + $kpi_preview.find('.target_deviation').css({ + "color": ks_color + }); + if (field.ks_target_view === "Progress Bar") { + $kpi_preview.find('#ks_progressbar').val(target_progress_deviation) + } + + return $kpi_preview; + }, + + ksPercentage: function(count_1, count_2, field, item_info, target_1, $kpi_preview, kpi_data) { + + if (field.ks_multiplier_active){ + count_1 = count_1 * field.ks_multiplier; + count_2 = count_2 * field.ks_multiplier; + } + var count = parseInt((count_1 / count_2) * 100); + if (field.ks_multiplier_active){ + count = count * field.ks_multiplier; + } + item_info['count'] = count ? field_utils.format.integer(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"; + var 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; + $kpi_preview = $(QWeb.render("ks_kpi_template_2", item_info)); + $kpi_preview.find('.target_deviation').css({ + "color": ks_color + }); + if (field.ks_target_view === "Progress Bar") { + if (count) $kpi_preview.find('#ks_progressbar').val(count); + else $kpi_preview.find('#ks_progressbar').val(0); + } + + return $kpi_preview; + }, + + renderKpi: function(item, grid) { + var self = this; + var field = item; + var ks_date_filter_selection = field.ks_date_filter_selection; + if (field.ks_date_filter_selection === "l_none") 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].target; + var target_view = field.ks_target_view, + pre_view = field.ks_prev_view; + var 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); + var 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 ? field_utils.format.integer(deviation) + '%' : 0 + '%'; + } + if (field.ks_previous_period && ks_valid_date_selection.indexOf(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 ? field_utils.format.integer(parseInt((pre_diffrence / previous_period_data) * 100)) + '%' : "100%" + } + if (item.ks_info){ + var ks_description = item.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + item['ksIsDashboardManager'] = self.ks_dashboard_data.ks_dashboard_manager; + + item['ksIsUser'] = true; + if (item.ks_tv_play){ + 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; + } + } +// parseInt(Math.round((count_1 / target_1) * 100)) ? field_utils.format.integer(Math.round((count_1 / target_1) * 100)) : "0" + 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: item, + id: field.id, + count_1: KsGlobalFunction.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(ks_date_filter_selection) >= 0 ? field.ks_previous_period : false, + target: KsGlobalFunction.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, + + } + + if (item_info.target_deviation === Infinity) item_info.target_arrow = false; + item_info.target_progress_deviation = parseInt(item_info.target_progress_deviation) ? field_utils.format.integer(parseInt(item_info.target_progress_deviation)) : "0" + if (field.ks_multiplier_active){ + item_info['count_1'] = KsGlobalFunction._onKsGlobalFormatter(kpi_data[0]['record_data'] * field.ks_multiplier, field.ks_data_formatting, field.ks_precision_digits); + item_info['count_1_tooltip'] = kpi_data[0]['record_data'] * field.ks_multiplier + }else{ + item_info['count_1'] = KsGlobalFunction._onKsGlobalFormatter(kpi_data[0]['record_data'], field.ks_data_formatting, field.ks_precision_digits); + } + item_info['target'] = KsGlobalFunction._onKsGlobalFormatter(kpi_data[0].target, field.ks_data_formatting, 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 = KsGlobalFunction._onKsGlobalFormatter(ks_record_count, field.ks_data_formatting, field.ks_precision_digits); + ks_data = KsGlobalFunction.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+" "+KsGlobalFunction._onKsGlobalFormatter(ks_record_count, field.ks_data_formatting, field.ks_precision_digits); + }else { + item_info['count_1']= KsGlobalFunction._onKsGlobalFormatter(ks_record_count, field.ks_data_formatting, field.ks_precision_digits); + } + } + var $kpi_preview; + if (!kpi_data[1]) { + if (field.ks_target_view === "Number" || !field.ks_goal_enable) { + $kpi_preview = $(QWeb.render("ks_kpi_template", item_info)); + } else if (field.ks_target_view === "Progress Bar" && field.ks_goal_enable) { + $kpi_preview = $(QWeb.render("ks_kpi_template_3", item_info)); + $kpi_preview.find('#ks_progressbar').val(parseInt(item_info.target_progress_deviation)); + + } + + if (field.ks_goal_enable) { + if (acheive) { + $kpi_preview.find(".target_deviation").css({ + "color": "green", + }); + } else { + $kpi_preview.find(".target_deviation").css({ + "color": "red", + }); + } + } + if (field.ks_previous_period && String(previous_period_data) && ks_valid_date_selection.indexOf(ks_date_filter_selection) >= 0) { + if (pre_acheive) { + $kpi_preview.find(".pre_deviation").css({ + "color": "green", + }); + } else { + $kpi_preview.find(".pre_deviation").css({ + "color": "red", + }); + } + } + if ($kpi_preview.find('.ks_target_previous').children().length !== 2) { + $kpi_preview.find('.ks_target_previous').addClass('justify-content-center'); + } + } else { + switch (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(KsGlobalFunction.ksNumFormatter(count_1 * field.ks_multiplier, 1)) + "/" + String(KsGlobalFunction.ksNumFormatter(count_2 * field.ks_multiplier, 1)); + var data1 = KsGlobalFunction._onKsGlobalFormatter(count_1 * field.ks_multiplier, field.ks_data_formatting, field.ks_precision_digits); + var data2 = KsGlobalFunction._onKsGlobalFormatter(count_2 * field.ks_multiplier, field.ks_data_formatting, 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 = KsGlobalFunction.ks_monetary(data1, ks_currency_id); + data2 = KsGlobalFunction.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(KsGlobalFunction._onKsGlobalFormatter(count_1*field.ks_multiplier, field.ks_data_formatting, field.ks_precision_digits)) + "/" + String(KsGlobalFunction._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(KsGlobalFunction.ksNumFormatter(count_1, 1)) + "/" + String(KsGlobalFunction.ksNumFormatter(count_2, 1)); + var data1 = KsGlobalFunction._onKsGlobalFormatter(count_1 , field.ks_data_formatting, field.ks_precision_digits); + var data2 = KsGlobalFunction._onKsGlobalFormatter(count_2 , field.ks_data_formatting, 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 = KsGlobalFunction.ks_monetary(data1, ks_currency_id); + data2 = KsGlobalFunction.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(KsGlobalFunction._onKsGlobalFormatter(count_1, field.ks_data_formatting, field.ks_precision_digits)) + "/" + String(KsGlobalFunction._onKsGlobalFormatter(count_2, field.ks_data_formatting, field.ks_precision_digits)); + } + } + item_info['count_tooltip'] = count_tooltip; + + item_info['target_enable'] = false; + $kpi_preview = $(QWeb.render("ks_kpi_template_2", item_info)); + break; + case "Sum": + $kpi_preview = self.ksSum(count_1, count_2, item_info, field, target_1, $kpi_preview, kpi_data); + break; + case "Percentage": + $kpi_preview = self.ksPercentage(count_1, count_2, field, item_info, target_1, $kpi_preview, kpi_data); + break; + case "Ratio": + var gcd = self.ks_get_gcd(Math.round(count_1), Math.round(count_2)); + if (item.ks_data_formatting == 'exact'){ + if (count_1 && count_2) { + item_info['count_tooltip'] = count_1 / gcd + ":" + count_2 / gcd; + item_info['count'] = field_utils.format.float(count_1 / gcd, Float64Array,{digits: [0, field.ks_precision_digits]}) + ":" + field_utils.format.float(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'] = KsGlobalFunction.ksNumFormatter(count_1 / gcd, 1) + ":" + KsGlobalFunction.ksNumFormatter(count_2 / gcd, 1); + }else { + item_info['count_tooltip'] = (count_1) + ":" + count_2; + item_info['count'] = KsGlobalFunction.ksNumFormatter(count_1, 1) + ":" + KsGlobalFunction.ksNumFormatter(count_2, 1); + } + } + item_info['target_enable'] = false; + $kpi_preview = $(QWeb.render("ks_kpi_template_2", item_info)); + break; + } + } +// $kpi_preview.find('.ks_dashboarditem_id').css({ +// "background-color": ks_rgba_background_color, +// "color": ks_rgba_font_color, +// }); + this.ks_kpi_preview_background_style($kpi_preview, ks_rgba_background_color, ks_rgba_font_color, field); + if (field.ks_previous_period && String(previous_period_data) && ks_valid_date_selection.indexOf(ks_date_filter_selection) >= 0 && + (field.ks_goal_enable && field.ks_target_view === "Progress Bar")){ + $kpi_preview.addClass('ks_previous_period') + } + return $kpi_preview + + }, + + ks_kpi_preview_background_style: function($kpi_preview, ks_rgba_background_color, ks_rgba_font_color, field){ + $kpi_preview.find('.ks_dashboarditem_id').css({ + "background-color": ks_rgba_background_color, + "color": ks_rgba_font_color, + }); + }, + + ks_get_gcd: function(a, b) { + return (b == 0) ? a : this.ks_get_gcd(b, a % b); + }, + + _onKsInputChange: function(e) { + this.ksNewDashboardName = e.target.value + }, + + onKsDuplicateItemClick: function(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({ + model: 'ks_dashboard_ninja.item', + method: 'copy', + args: [parseInt(ks_item_id), { + 'ks_dashboard_ninja_board_id': parseInt(dashboard_id) + }], + }).then(function(result) { + self.displayNotification({ + title:_t("Item Duplicated"), + message:_t('Selected item is duplicated to ' + dashboard_name + ' .'), + type: 'success', + }); + $.when(self.ks_fetch_data()).then(function () { + self.ks_fetch_items_data().then(function (){ + self.ksRenderDashboard(); + }); + }); + }) + }, + + ksOnListItemInfoClick: function(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.do_action(action, { + on_reverse_breadcrumb: this.on_reverse_breadcrumb, + }); + }, + + onKsMoveItemClick: function(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({ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [parseInt(ks_item_id), { + 'ks_dashboard_ninja_board_id': parseInt(dashboard_id) + }], + }).then(function(result) { + self.displayNotification({ + title:_t("Item Moved"), + message:_t('Selected item is moved to ' + dashboard_name + ' .'), + type: 'success', + }); + $.when(self.ks_fetch_data()).then(function() { + $.when(self.ks_fetch_items_data()).then(function(){ + self.ks_remove_update_interval(); + self.ksRenderDashboard(); + self.ks_set_update_interval(); + }); + }); + }); + }, + + _KsGetDateValues: function() { + var self = this; + + //Setting Date Filter Selected Option in Date Filter DropDown Menu + var date_filter_selected = self.ks_dashboard_data.ks_date_filter_selection; + if (self.ksDateFilterSelection == 'l_none'){ + date_filter_selected = self.ksDateFilterSelection; +// $('.ks_date_input_fields').addClass("ks_hide"); + } + self.$el.find('#' + date_filter_selected).addClass("ks_date_filter_selected"); + self.$el.find('#ks_date_filter_selection').text(self.ks_date_filter_selections[date_filter_selected]); + + if (self.ks_dashboard_data.ks_date_filter_selection === 'l_custom') { + self.$el.find('.ks_date_input_fields').removeClass("ks_hide"); + self.$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.$el.find('.ks_date_input_fields').addClass("ks_hide"); + } + }, + + _onKsClearDateValues: function(ks_l_none=false) { + var self = this; + self.ksDateFilterSelection = 'l_none'; + self.ksDateFilterStartDate = false; + self.ksDateFilterEndDate = false; + + self.ks_fetch_items_data().then(function () { +// self.ksRenderDashboard(); + $('.ks_date_input_fields').addClass("ks_hide"); + $('.ks_date_filter_dropdown').removeClass("ks_btn_first_child_radius"); + + var res = {}; + for (const [key, value] of Object.entries(self.ks_dashboard_data.ks_item_data)) { + if (value.ks_dashboard_item_type != "ks_to_do") { + res[key] = value; + } + } + self.ksUpdateDashboardItem(Object.keys(res)) + }); + var context = { + ksDateFilterSelection: self.ksDateFilterSelection, + ksDateFilterStartDate: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + self.state['user_context']=context + + }, + + + _renderDateFilterDatePicker: function() { + var self = this; + self.$el.find(".ks_dashboard_link").removeClass("ks_hide"); + var startDate = self.ks_dashboard_data.ks_dashboard_start_date ? moment.utc(self.ks_dashboard_data.ks_dashboard_start_date).local() : moment(); + var endDate = self.ks_dashboard_data.ks_dashboard_end_date ? moment.utc(self.ks_dashboard_data.ks_dashboard_end_date).local() : moment(); + + this.ksStartDatePickerWidget = new(datepicker.DateTimeWidget)(this); + + this.ksStartDatePickerWidget.appendTo(self.$el.find(".ks_date_input_fields")).then((function() { + this.ksStartDatePickerWidget.$el.addClass("ks_btn_middle_child o_input"); + this.ksStartDatePickerWidget.$el.find("input").attr("placeholder", "Start Date"); + this.ksStartDatePickerWidget.setValue(startDate); + this.ksStartDatePickerWidget.on("datetime_changed", this, function() { + self.$el.find(".apply-dashboard-date-filter").removeClass("ks_hide"); + self.$el.find(".clear-dashboard-date-filter").removeClass("ks_hide"); + }); + }).bind(this)); + + this.ksEndDatePickerWidget = new(datepicker.DateTimeWidget)(this); + this.ksEndDatePickerWidget.appendTo(self.$el.find(".ks_date_input_fields")).then((function() { + this.ksEndDatePickerWidget.$el.addClass("ks_btn_last_child o_input"); + this.ksStartDatePickerWidget.$el.find("input").attr("placeholder", "Start Date"); + this.ksEndDatePickerWidget.setValue(endDate); + this.ksEndDatePickerWidget.on("datetime_changed", this, function() { + self.$el.find(".apply-dashboard-date-filter").removeClass("ks_hide"); + self.$el.find(".clear-dashboard-date-filter").removeClass("ks_hide"); + }); + }).bind(this)); + + self._KsGetDateValues(); + }, + + _onKsApplyDateFilter: function(e) { + var self = this; + var start_date = self.ksStartDatePickerWidget.$input.val(); + var end_date = self.ksEndDatePickerWidget.$input.val(); + $('.ks_dashboard_item_drill_up').addClass("d-none") + if (start_date === "Invalid date") { + alert("Invalid Date is given in Start Date.") + } else if (end_date === "Invalid date") { + alert("Invalid Date is given in End Date.") + } else if (self.$el.find('.ks_date_filter_selected').attr('id') !== "l_custom") { + + self.ksDateFilterSelection = self.$el.find('.ks_date_filter_selected').attr('id'); + var res = {}; + for (const [key, value] of Object.entries(self.ks_dashboard_data.ks_item_data)) { + if (value.ks_dashboard_item_type != "ks_to_do") { + res[key] = value; + } + } + var context = { + ksDateFilterSelection: self.ksDateFilterSelection, + ksDateFilterStartDate: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + self.state['user_context']=context + self.ks_fetch_items_data().then(function(result){ + self.ksUpdateDashboardItem(Object.keys(res)); + self.$el.find(".apply-dashboard-date-filter").addClass("ks_hide"); + self.$el.find(".clear-dashboard-date-filter").addClass("ks_hide"); + + }); + } else { + if (start_date && end_date) { + if (moment(start_date, self.datetime_format) <= moment(end_date, self.datetime_format)) { + var start_date = new moment(start_date, self.datetime_format).format("YYYY-MM-DD H:m:s"); + var end_date = new moment(end_date, self.datetime_format).format("YYYY-MM-DD H:m:s"); + if (start_date === "Invalid date" || end_date === "Invalid date"){ + alert(_t("Invalid Date")); + }else{ + self.ksDateFilterSelection = self.$el.find('.ks_date_filter_selected').attr('id'); + self.ksDateFilterStartDate = start_date; + self.ksDateFilterEndDate = end_date; + + self.ks_fetch_items_data().then(function(result){ + var res = {}; + for (const [key, value] of Object.entries(self.ks_dashboard_data.ks_item_data)) { + if (value.ks_dashboard_item_type != "ks_to_do") { + res[key] = value; + } + } + var context = { + ksDateFilterSelection: self.ksDateFilterSelection, + ksDateFilterStartDate: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + self.state['user_context']=context + self.ksUpdateDashboardItem(Object.keys(res)); + self.$el.find(".apply-dashboard-date-filter").addClass("ks_hide"); + self.$el.find(".clear-dashboard-date-filter").addClass("ks_hide"); + }); + + } + + } else { + alert(_t("Start date should be less than end date")); + } + } else { + alert(_t("Please enter start date and end date")); + } + } + }, + + _ksOnDateFilterMenuSelect: function(e) { + if (e.target.id !== 'ks_date_selector_container') { + var self = this; + _.each($('.ks_date_filter_selected'), function($filter_options) { + $($filter_options).removeClass("ks_date_filter_selected") + }); + $(e.target.parentElement).addClass("ks_date_filter_selected"); + $('#ks_date_filter_selection').text(self.ks_date_filter_selections[e.target.parentElement.id]); + + if (e.target.parentElement.id !== "l_custom") { + e.target.parentElement.id === "l_none" ? self._onKsClearDateValues(true) : self._onKsApplyDateFilter(); + $('.ks_date_input_fields').addClass("ks_hide"); + $('.ks_date_filter_dropdown').removeClass("ks_btn_first_child_radius"); + + } else if (e.target.parentElement.id === "l_custom") { + $("#ks_start_date_picker").val(null).removeClass("ks_hide"); + $("#ks_end_date_picker").val(null).removeClass("ks_hide"); + $('.ks_date_input_fields').removeClass("ks_hide"); + $('.ks_date_filter_dropdown').addClass("ks_btn_first_child_radius"); + self.$el.find(".apply-dashboard-date-filter").removeClass("ks_hide"); + self.$el.find(".clear-dashboard-date-filter").removeClass("ks_hide"); + } + } + }, + + ksChartExportXlsCsv: function(e) { + var chart_id = e.currentTarget.dataset.chartId; + var name = this.ks_dashboard_data.ks_item_data[chart_id].name; + var context = this.getContext(); + if (this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type === 'ks_list_view'){ + var params = this.ksGetParamsForItemFetch(parseInt(chart_id)); + var data = { + "header": name, + "chart_data": this.ks_dashboard_data.ks_item_data[chart_id].ks_list_view_data, + "ks_item_id": chart_id, + "ks_export_boolean": true, + "context": context, + 'params':params, + } + }else{ + var data = { + "header": name, + "chart_data": this.ks_dashboard_data.ks_item_data[chart_id].ks_chart_data, + } + } + + framework.blockUI(); + this.getSession().get_file({ + url: '/ks_dashboard_ninja/export/' + e.currentTarget.dataset.format, + data: { + data: JSON.stringify(data) + }, + complete: framework.unblockUI, + error: (error) => this.call('crash_manager', 'rpc_error', error), + }); + }, + + ksChartExportPdf : function(e){ + var self = this; + var chart_id = e.currentTarget.dataset.chartId; + var name = this.ks_dashboard_data.ks_item_data[chart_id].name; + var base64_image + if(this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_bullet_chart" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_funnel_chart" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_flower_view" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_radialBar_chart" || this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type == "ks_map_view"){ + base64_image = (this.chart_container[chart_id].root.dom).querySelector("canvas").toDataURL("image/png") + }else{ + base64_image = this.chart_container[chart_id].toBase64Image(); + } + var $ks_el = $($(self.$el.find(".grid-stack-item[gs-id=" + chart_id + "]")).find('.ks_chart_card_body')); + var ks_height = $ks_el.height() + var ks_image_def = { + content: [{ + image: base64_image, + width: 500, + height: ks_height, + }], + images: { + bee: base64_image + } + }; + pdfMake.createPdf(ks_image_def).download(name + '.pdf'); + }, + + ksItemExportJson: function(e) { + var itemId = $(e.target).parents('.ks_dashboard_item_button_container')[0].dataset.item_id; + var name = this.ks_dashboard_data.ks_item_data[itemId].name; + var data = { + 'header': name, + item_id: itemId, + } + framework.blockUI(); + this.getSession().get_file({ + url: '/ks_dashboard_ninja/export/item_json', + data: { + data: JSON.stringify(data) + }, + complete: framework.unblockUI, + error: (error) => this.call('crash_manager', 'rpc_error', error), + }); + e.stopPropagation(); + }, + + //List View pagination records + ksLoadMoreRecords: function(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; + + if (itemId in self.ksUpdateDashboard) { + clearInterval(self.ksUpdateDashboard[itemId]) + delete self.ksUpdateDashboard[itemId]; + } + var params = self.ksGetParamsForItemFetch(parseInt(itemId)); + this._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'ks_get_list_view_data_offset', + context: self.getContext(), + args: [parseInt(itemId), { + ks_intial_count: ks_intial_count, + offset: ks_offset, + }, parseInt(self.ks_dashboard_id), params], + }).then(function(result) { + var item_data = self.ks_dashboard_data.ks_item_data[itemId]; + self.ks_dashboard_data.ks_item_data[itemId]['ks_list_view_data'] = result.ks_list_view_data; + var item_view = self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"); + item_view.find('.card-body').empty(); + item_view.find('.card-body').append(self.renderListViewData(item_data)); + $(e.currentTarget).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.currentTarget.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.currentTarget).addClass('ks_event_offer_list'); + } + }); + }, + + ksLoadPreviousRecords: function(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; + if (ks_offset <= 0) { + var updateValue = self.ks_dashboard_data.ks_set_interval; + if (updateValue) { + var updateinterval = setInterval(function() { + self.ksFetchUpdateItem(itemId) + }, updateValue); + self.ksUpdateDashboard[itemId] = updateinterval; + } + } + var params = self.ksGetParamsForItemFetch(parseInt(itemId)); + this._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'ks_get_list_view_data_offset', + context: self.getContext(), + args: [parseInt(itemId), { + ks_intial_count: ks_intial_count, + offset: ks_offset, + }, parseInt(self.ks_dashboard_id), params], + }).then(function(result) { + var item_data = self.ks_dashboard_data.ks_item_data[itemId]; + self.ks_dashboard_data.ks_item_data[itemId]['ks_list_view_data'] = result.ks_list_view_data; + var item_view = self.$el.find(".grid-stack-item[gs-id=" + item_data.id + "]"); + item_view.find('.card-body').empty(); + item_view.find('.card-body').append(self.renderListViewData(item_data)); + $(e.currentTarget).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.currentTarget.parentElement).find('.ks_load_next').removeClass('ks_event_offer_list'); + if (result.offset === 1) { + $(e.currentTarget).addClass('ks_event_offer_list'); + } + }); + }, + createaidash: function(ev){ + var self= this; + var action = { + name: _t('Generate items with AI'), + type: 'ir.actions.act_window', + res_model: 'ks_dashboard_ninja.arti_int', + domain: [], + context: { + 'ks_dashboard_id':this.ks_dashboard_id + }, + views: [ + [false, 'form'] + ], + view_mode: 'form', + target: 'new', + } + self.do_action(action) + + }, + createaidashboard: function(ev){ + var self= this; + var 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.do_action(action) + } + + }); + + core.action_registry.add('ks_dashboard_ninja', KsDashboardNinja); + + patch(WebClient.prototype, 'ks_dn.WebClient', { + async loadRouterState(...args) { + var self = this; + const sup = await this._super(...args); + const ks_reload_menu = async (id) => { + this.menuService.reload().then(() => { + self.menuService.selectMenu(id); + }); + } + this.actionService.ksDnReloadMenu = ks_reload_menu; + return sup; + } + + }); + + return KsDashboardNinja; +}); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js b/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js new file mode 100644 index 000000000..0e7d5aedd --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja_new.js @@ -0,0 +1,1619 @@ +/** @odoo-module **/ + +import { _t } from "@web/core/l10n/translation"; +import { Component, onWillStart, useState ,onMounted, onWillRender, useRef, useEffect,onWillUnmount } from "@odoo/owl"; +import { registry } from "@web/core/registry"; +import { jsonrpc } from "@web/core/network/rpc_service"; +import { useService } from "@web/core/utils/hooks"; +import { loadJS,loadCSS } from "@web/core/assets"; +import { localization } from "@web/core/l10n/localization"; +import { session } from "@web/session"; +import { download } from "@web/core/network/download"; +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 { isBrowserChrome, 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 {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 { 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"; + + +export class KsDashboardNinja extends Component { + + setup() { + this.actionService = useService("action"); + this.dialogService = useService("dialog"); + this.notification = useService("notification"); + this._rpc = useService("rpc"); + this.dialogService = useService("dialog"); + this.header = useRef("ks_dashboard_header"); + 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.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, + }; + 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:[], + update:false, + ksDateFilterSelection :false, + pre_defined_filter :{}, + ksDateFilterStartDate: DateTime.now(), + ksDateFilterEndDate:DateTime.now() + }) + this.ksChartColorOptions = ['default', 'cool', 'warm', 'neon']; + this.ksDateFilterSelection = false; + this.ksDateFilterStartDate = false; + this.ksDateFilterEndDate = false; + this.ksUpdateDashboard = {}; + $("head").append(''); + 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: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + this.dn_state = {} + this.dn_state['user_context']=context + this.ks_speeches = []; + onWillStart(this.willStart); + onWillRender(this.dashboard_mount); + onWillUnmount(()=>this.ks_switch_default_dashboard()); + + onMounted(() => { + this.grid_initiate(); + var filter_date_data = this.getObjectFromCookie('FilterDateData' + this.ks_dashboard_id); + if (filter_date_data != null){ + $(this.header.el).find('.ks_date_filter_selected').removeClass('ks_date_filter_selected'); + $('#ks_date_filter_selection').text(this.ks_date_filter_selections[filter_date_data]); + + var element_selected = document.getElementById(filter_date_data); + element_selected.classList.add('ks_date_filter_selected') + this.state.ksDateFilterSelection = filter_date_data; + if(filter_date_data==='l_custom'){ + var custom_range = this.getObjectFromCookie('custom_range' + this.ks_dashboard_id); + if(custom_range){ + this.state.ksDateFilterStartDate = custom_range['start_date'] + this.state.ksDateFilterEndDate = custom_range['end_date'] + } + $('.ks_date_input_fields').removeClass("ks_hide"); + $('.ks_date_filter_dropdown').addClass("ks_btn_first_child_radius"); + } + + } + + if (this.getObjectFromCookie('FilterDateData' + this.ks_dashboard_id) || this.getObjectFromCookie('FilterOrderData' + this.ks_dashboard_id)){ + this._onKsApplyDateFilter(); + } + }); + } + + + willStart(){ + var self = this; + var def; + var storedData = this.getObjectFromCookie('FilterOrderData' + self.ks_dashboard_id); + 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().then(function(){ + if(storedData != null ){ + self.ks_dashboard_data.ks_dashboard_domain_data = storedData; + } + }); + }); + }); + } + + grid_initiate(){ + var self=this; + const ks_element = this.main_body.el; + var $gridstackContainer = $(".grid-stack"); + if($gridstackContainer.length){ + this.grid = GridStack.init(this.gridstack_options,$gridstackContainer[0]); + 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:2, 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:5,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:3, h:2,autoPosition:true,minW:3,maxW:null,minH:2,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}); + } + Object.values(ks_element.querySelectorAll(".ks_dashboard_item_button_container")).map((item) => { + $(item).addClass('d-none') + $(item).removeClass('d-md-flex') + }) + Object.values(ks_element.querySelectorAll(".ks_pager_name")).map((item) => { + $(item).addClass('d-none') + }) + + + } + } + this.grid.setStatic(true); + } + this.ksRenderDashboard(); + // Events // + + Object.values(ks_element.querySelectorAll(".ks_duplicate_item")).map((item) => { item.addEventListener('click', this.onKsDuplicateItemClick.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_move_item")).map((item) => { item.addEventListener('click', this.onKsMoveItemClick.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_dashboard_item_delete")).map((item) => { item.addEventListener('click', this._onKsDeleteItemClick.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_chart_xls_csv_export")).map((item) => { item.addEventListener('click', this.ksChartExportXlsCsv.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_chart_pdf_export")).map((item) => { item.addEventListener('click', this.ksChartExportPdf.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_chart_image_export")).map((item) => { item.addEventListener('click', this.ksChartExportimage.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_chart_json_export")).map((item) => { item.addEventListener('click', this.ksItemExportJson.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_dashboard_quick_edit_action_popup")).map((item) => { item.addEventListener('click', this.onEditItemTypeClick.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_dashboard_item_customize")).map((item) => { item.addEventListener('click', this.onEditItemTypeClick.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_dashboard_menu_container")).map((item) => { item.addEventListener('click', this.stoppropagation.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_item_description")).map((item) => { item.addEventListener('click', this.stoppropagation.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_item_click")).map((item) => { item.addEventListener('click', this._onKsItemClick.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_dashboard_item_action")).map((item) => { item.addEventListener('click', this.ks_dashboard_item_action.bind(this))}) + Object.values(ks_element.querySelectorAll(".ks_dashboard_item_chart_info")).map((item) => { item.addEventListener('click', this.onChartMoreInfoClick.bind(this))}) +// Object.values((self.header.el).querySelectorAll(".ks_custom_filter_field_selector")).map((item) => { item.addEventListener('change', this.ksOnCustomFilterFieldSelect.bind(this))}) + + } + + 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 jsonrpc("/web/dataset/call_kw",{ + model: 'ks_dashboard_ninja.board', + method: 'ks_fetch_dashboard_data', + args: [self.ks_dashboard_id], + kwargs : {context:self.getContext()}, +// context: self.getContext() + }).then(function(result) { + // result = self.normalize_dn_data(result); + self.ks_dashboard_data = result; + 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 + 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; + } + }) + } + }); + } + + dashboard_mount(){ + var self = this; +// var items = self.ksSortItems(self.ks_dashboard_data.ks_item_data) + var items = Object.values(self.ks_dashboard_data.ks_item_data) + self.state.ks_dashboard_items = items + self.ks_dashboard_data['context'] = self.getContext() + + } + + 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(jsonrpc("/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()} + }).then(function(result){ + self.ks_dashboard_data.ks_item_data[item_id] = result[item_id]; + self.state.ks_show_create_layout_option = (Object.keys(self.ks_dashboard_data.ks_item_data).length > 0) && self.ks_dashboard_data.ks_dashboard_manager + })); + }); + self.state.ks_dashboard_name = self.ks_dashboard_data.name, + self.state.ks_multi_layout = self.ks_dashboard_data.multi_layouts, + self.state.ks_dash_name = self.ks_dashboard_data.name, + self.state.ks_dashboard_manager = self.ks_dashboard_data.ks_dashboard_manager, + self.state.date_selection_data = self.ks_date_filter_selections, + self.state.date_selection_order = self.ks_date_filter_selection_order, + self.state.ks_show_layout = self.ks_dashboard_data.ks_dashboard_manager && self.ks_dashboard_data.ks_child_boards && true, + self.state.ks_selected_board_id = self.ks_dashboard_data.ks_selected_board_id, + self.state.ks_child_boards = self.ks_dashboard_data.ks_child_boards, + self.state.ks_dashboard_data = self.ks_dashboard_data, + self.state.ks_dn_pre_defined_filters = Object.values(self.ks_dashboard_data.ks_dashboard_pre_domain_filter).sort(function(a, b){return a.sequence - b.sequence}), + self.state.ks_dashboard_item_length = self.ks_dashboard_data.ks_dashboard_items_ids.length + self.state.update = false + self.state.ksDateFilterSelection = self.state.ksDateFilterSelection == false ? 'none' : self.state.ksDateFilterSelection, + self.state.pre_defined_filter = {} + self.state.custom_filter = {} + var custom_range = this.getObjectFromCookie('custom_range' + this.ks_dashboard_id); + if(custom_range){ + this.state.ksDateFilterStartDate = parseDateTime(custom_range['start_date'], self.datetime_format) + this.state.ksDateFilterEndDate = parseDateTime(custom_range['end_date'], self.datetime_format) + }else{ + self.state.ksDateFilterStartDate = DateTime.now() + self.state.ksDateFilterEndDate = DateTime.now() + } + + self.state.ks_user_name = session.name + 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"); + } + if(!self.state.ks_dashboard_manager){ + $(self.header.el).find('#ks_dashboard_title').addClass("ks_user") + } + 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(); + console.log("Print") + } + + loadDashboardData(date = false){ + var self = this; + $(self.header.el).find(".apply-dashboard-date-filter").removeClass("ks_hide"); + $(self.header.el).find(".clear-dashboard-date-filter").removeClass("ks_hide"); + } + + _KsGetDateValues() { + var self = this; + //Setting Date Filter Selected Option in Date Filter DropDown Menu + 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"); + $(self.header.el).find('#ks_date_filter_selection').text(self.ks_date_filter_selections[date_filter_selected]); + + 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"); + } + } + + _ksOnDateFilterMenuSelect(e) { + if (e.target.id !== 'ks_date_selector_container') { + var self = this; + $.each($('.ks_date_filter_selected'), function(idx, $itm) { + $($itm).removeClass("ks_date_filter_selected") + }); + $(e.target.parentElement).addClass("ks_date_filter_selected"); + $('#ks_date_filter_selection').text(self.ks_date_filter_selections[e.target.parentElement.id]); + + if (e.target.parentElement.id !== "l_custom") { + e.target.parentElement.id === "l_none" ? self._onKsClearDateValues(true) : self._onKsApplyDateFilter(); + $('.ks_date_input_fields').addClass("ks_hide"); + $('.ks_date_filter_dropdown').removeClass("ks_btn_first_child_radius"); + + } else if (e.target.parentElement.id === "l_custom") { + $("#ks_start_date_picker").val(null).removeClass("ks_hide"); + $("#ks_end_date_picker").val(null).removeClass("ks_hide"); + $('.ks_date_input_fields').removeClass("ks_hide"); + $('.ks_date_filter_dropdown').addClass("ks_btn_first_child_radius"); + $(self.header.el).find(".apply-dashboard-date-filter").removeClass("ks_hide"); + $(self.header.el).find(".clear-dashboard-date-filter").removeClass("ks_hide"); + } + if(self.state.ksDateFilterSelection === 'l_none'){ + this.eraseCookie('FilterDateData' + self.ks_dashboard_id); + }else{ + this.setObjectInCookie('FilterDateData' + self.ks_dashboard_id, self.state.ksDateFilterSelection, 1); + } + } + } + + _onKsApplyDateFilter(e) { + var self = this; + var start_date = $('#ks_btn_middle_child').val(); + var end_date = $('#ks_btn_last_child').val(); + $('.ks_dashboard_item_drill_up').addClass("d-none") + if (start_date === "Invalid date") { + alert("Invalid Date is given in Start Date.") + } else if (end_date === "Invalid date") { + alert("Invalid Date is given in End Date.") + } else if ($(self.header.el).find('.ks_date_filter_selected').attr('id') !== "l_custom") { + self.ksDateFilterSelection = $(self.header.el).find('.ks_date_filter_selected').attr('id'); + var res = {}; + for (const [key, value] of Object.entries(self.ks_dashboard_data.ks_item_data)) { + if (value.ks_dashboard_item_type != "ks_to_do") { + res[key] = value; + } + } + var context = { + ksDateFilterSelection: self.ksDateFilterSelection, + ksDateFilterStartDate: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + self.dn_state['user_context']=context + $(self.header.el).find(".apply-dashboard-date-filter").addClass("ks_hide"); + $(self.header.el).find(".clear-dashboard-date-filter").addClass("ks_hide"); + self.state.ksDateFilterSelection = $(self.header.el).find('.ks_date_filter_selected').attr('id'); + self.state.pre_defined_filter = {} + self.state.custom_filter = {} + } else { + if (start_date && end_date) { + if (parseDateTime(start_date,self.datetime_format) <= parseDateTime(end_date, self.datetime_format)) { +// var start_date = parseDateTime(start_date, self.datetime_format).format("YYYY-MM-DD H:m:s"); + var start_date = formatDateTime(parseDateTime(start_date, self.datetime_format), { format: "yyyy-MM-dd HH:mm:ss"}) + var end_date = formatDateTime(parseDateTime(end_date, self.datetime_format), { format: "yyyy-MM-dd HH:mm:ss" }) +// var end_date = formatDateTime(end_date, self.datetime_format).format("YYYY-MM-DD H:m:s"); + if (start_date === "Invalid date" || end_date === "Invalid date"){ + alert(_t("Invalid Date")); + }else{ + self.ksDateFilterSelection = $(self.header.el).find('.ks_date_filter_selected').attr('id'); + self.ksDateFilterStartDate = start_date; + self.ksDateFilterEndDate = end_date; + this.setObjectInCookie('custom_range' + self.ks_dashboard_id, {'start_date': start_date, 'end_date':end_date}, 1); + var res = {}; + for (const [key, value] of Object.entries(self.ks_dashboard_data.ks_item_data)) { + if (value.ks_dashboard_item_type != "ks_to_do") { + res[key] = value; + } + } + var context = { + ksDateFilterSelection: self.ksDateFilterSelection, + ksDateFilterStartDate: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + self.dn_state['user_context']=context + $(self.header.el).find(".apply-dashboard-date-filter").addClass("ks_hide"); + $(self.header.el).find(".clear-dashboard-date-filter").addClass("ks_hide"); + self.state.ksDateFilterSelection = $(self.header.el).find('.ks_date_filter_selected').attr('id'); + this.setObjectInCookie('FilterDateData' + self.ks_dashboard_id, self.state.ksDateFilterSelection, 1); + self.state.pre_defined_filter = {} + self.state.custom_filter = {} + self.state.ksDateFilterStartDate = parseDateTime(self.ksDateFilterStartDate,self.datetime_format); + self.state.ksDateFilterEndDate = parseDateTime(self.ksDateFilterEndDate,self.datetime_format); + } + } else { + alert(_t("Start date should be less than end date")); + } + } else { + alert(_t("Please enter start date and end date")); + } + } + } + + 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=/"; + } + + setObjectInCookie(name, object, days) { + var jsonString = JSON.stringify(object); + this.setCookie(name, jsonString, days); + } + + + 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; + } + + getObjectFromCookie(name) { + var jsonString = this.getCookie(name); + return jsonString ? JSON.parse(jsonString) : null; + } + + _onKsClearDateValues(ks_l_none=false) { + var self = this; + self.ksDateFilterSelection = 'l_none'; + self.ksDateFilterStartDate = false; + self.ksDateFilterEndDate = false; + var res = {}; + for (const [key, value] of Object.entries(self.ks_dashboard_data.ks_item_data)) { + if (value.ks_dashboard_item_type != "ks_to_do") { + res[key] = value; + } + } + var context = { + ksDateFilterSelection: self.ksDateFilterSelection, + ksDateFilterStartDate: self.ksDateFilterStartDate, + ksDateFilterEndDate: self.ksDateFilterEndDate, + } + self.dn_state['user_context']=context + $('.ks_date_input_fields').addClass("ks_hide"); + $('.ks_date_filter_dropdown').removeClass("ks_btn_first_child_radius"); + self.state.ksDateFilterSelection = 'l_none'; + self.state.pre_defined_filter = {}; + self.state.custom_filter = {} + $(self.header.el).find(".apply-dashboard-date-filter").addClass("ks_hide"); + $(self.header.el).find(".clear-dashboard-date-filter").addClass("ks_hide"); + + } + + 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)); + } + + onChartMoreInfoClick(e) { + var self = this; + var item_id = e.currentTarget.dataset.itemId; + var item_data = self.ks_dashboard_data.ks_item_data[item_id]; + var groupBy = item_data.ks_chart_groupby_type === 'date_type' ? item_data.ks_chart_relation_groupby_name + ':' + item_data.ks_chart_date_groupby : item_data.ks_chart_relation_groupby_name; + var domain = JSON.parse(item_data.ks_chart_data).previous_domain + + if (item_data.ks_show_records) { + if (item_data.action) { + + if (!item_data.ks_is_client_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'] = item_data.ks_domain || []; + action['search_view_id'] = [action.search_view_id, 'search'] + }else{ + var action = Object.assign({}, item_data.action[0]); + if (action.params){ + action.params.default_active_id || 'mailbox_inbox'; + }else{ + action.params = { + 'default_active_id': 'mailbox_inbox' + } + action.context = {} + action.context.params = { + 'active_model': false + }; + } + } + } 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', + } + } + self.actionService.doAction(action, { + on_reverse_breadcrumb: self.on_reverse_breadcrumb, + }); + } + } + + + 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', + }); + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + + }) + e.stopPropagation() + + } + + onKsMoveItemClick(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/write",{ + model: 'ks_dashboard_ninja.item', + method: 'write', + args: [parseInt(ks_item_id), { + 'ks_dashboard_ninja_board_id': parseInt(dashboard_id) + }], + kwargs:{} + }).then(function(result) { + self.notification.add(_t('Selected item is moved to ' + dashboard_name + ' .'),{ + title:_t("Item Moved"), + type: 'success', + }); + + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + + }); + e.stopPropagation() + } + + _onKsItemClick(e){ + var self = this; + // To Handle only allow item to open when not clicking on item + if (self.ksAllowItemClick) { + e.preventDefault(); + if (e.target.title != "Customize Item") { + var item_id = parseInt(e.currentTarget.firstElementChild.id); + var 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') { + + if (item_data.action) { + if (!item_data.ks_is_client_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'] = item_data.ks_domain || []; + action['search_view_id'] = [action.search_view_id, 'search'] + }else{ + var action = Object.assign({}, item_data.action[0]); + if (action.params){ + action.params.default_active_id || 'mailbox_inbox'; + }else{ + action.params = { + 'default_active_id': 'mailbox_inbox' + } + action.context = {} + action.context.params = { + 'active_model': false + }; + } + } + + } else { + var 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 (item_data.ks_is_client_action){ + self.actionService.doAction(action,{}) + }else{ + self.actionService.doAction(action, { + on_reverse_breadcrumb: self.on_reverse_breadcrumb, + }); + } + } + } + } else { + self.ksAllowItemClick = true; + } + } + ks_dashboard_item_action(e){ + this.ksAllowItemClick = false; + } + + _onKsDeleteItemClick(e) { + var self = this; + var item = $($(e.currentTarget).parentsUntil('.grid-stack').slice(-1)[0]) + var id = parseInt($($(e.currentTarget).parentsUntil('.grid-stack').slice(-1)[0]).attr('gs-id')); + self.ks_delete_item(id, item); + e.stopPropagation(); + } + + ks_delete_item(id, item) { + var self = this; + this.dialogService.add(ConfirmationDialog, { + body: _t("Are you sure that you want to remove this item?"), + confirm: () => { + self._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. + self.ks_remove_update_interval(); + delete self.ks_dashboard_data.ks_item_data[id]; + self.grid.removeWidget(item); + + if (Object.keys(self.ks_dashboard_data.ks_item_data).length > 0) { + self._ksSaveCurrentLayout(); + } + + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + + }); + + }, + cancel: () => {}, + }); + } + removeitems(){ + var self = this; + var ks_items = Object.values((self.main_body.el).querySelectorAll(".grid-stack-item")); + ks_items.forEach((item) =>{ + self.grid.removeWidget(item); + }) + } + + _ksSetCurrentLayoutClick(){ + var self = this; + this.ks_dashboard_data.ks_selected_board_id = $(self.header.el).find("#ks_dashboard_layout_dropdown_container .ks_layout_selected").data('ks_layout_id'); + $(self.header.el).find(".ks_dashboard_top_menu .ks_dashboard_top_settings").removeClass("ks_hide"); + $(self.header.el).find(".ks_dashboard_top_menu .ks_am_content_element").removeClass("ks_hide"); + $(self.header.el).find(".ks_dashboard_layout_edit_mode_settings").addClass("ks_hide"); +// $('#ks_dashboard_title_input').val(this.ks_dashboard_data.ks_child_boards[this.ks_dashboard_data.ks_selected_board_id][0]); + this.ks_dashboard_data.name = this.ks_dashboard_data.ks_child_boards[this.ks_dashboard_data.ks_selected_board_id][0]; + + 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.ks_dashboard_data.ks_selected_board_id, + }], + kwargs:{}, + }).then(function(result){ + window.location.reload(); + }); + } + + _ksSetDiscardCurrentLayoutClick(){ + this.ksOnLayoutSelection(this.ks_dashboard_data.ks_selected_board_id); + $(this.header.el).find(".ks_dashboard_top_menu .ks_dashboard_top_settings").removeClass("ks_hide"); + $(this.header.el).find(".ks_dashboard_top_menu .ks_am_content_element").removeClass("ks_hide"); + $(this.header.el).find(".ks_dashboard_layout_edit_mode_settings").addClass("ks_hide"); + $(this.header.el).find(".ks_dashboard_top_menu .ks_dashboard_edit_layout").removeClass("ks_hide"); + } + + _ksSaveCurrentLayout() { + var self = this; + var grid_config = self.ks_get_current_gridstack_config(); + var model = 'ks_dashboard_ninja.child_board'; + var 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()) { + this._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:{}, + }) + } + } + + ks_get_current_gridstack_config(){ + var self = this; + if (document.querySelector('.grid-stack') && document.querySelector('.grid-stack').gridstack){ + var items = document.querySelector('.grid-stack').gridstack.el.gridstack.engine.nodes; + } + var 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; + } + + ////////////////////////////// Export functions //////////////////////////////////////////// + async ksChartExportXlsCsv(e) { + var chart_id = e.currentTarget.dataset.chartId; + var name = this.ks_dashboard_data.ks_item_data[chart_id].name; + var context = this.getContext(); + if (this.ks_dashboard_data.ks_item_data[chart_id].ks_dashboard_item_type === 'ks_list_view'){ + var params = this.ksGetParamsForItemFetch(parseInt(chart_id)); + var data = { + "header": name, + "chart_data": this.ks_dashboard_data.ks_item_data[chart_id].ks_list_view_data, + "ks_item_id": chart_id, + "ks_export_boolean": true, + "context": context, + 'params':params, + } + }else{ + var data = { + "header": name, + "chart_data": this.ks_dashboard_data.ks_item_data[chart_id].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 = e.currentTarget.dataset.chartId; + var name = this.ks_dashboard_data.ks_item_data[chart_id].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.main_body.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, + }], + images: { + bee: ks_image + } + }; + pdfMake.createPdf(ks_image_def).download(name + '.pdf'); + }) + + } + ksChartExportimage(e){ + var self = this; + var chart_id = e.currentTarget.dataset.chartId; + var name = this.ks_dashboard_data.ks_item_data[chart_id].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) { + e.stopPropagation(); + var itemId = $(e.target).parents('.ks_dashboard_item_button_container')[0].dataset.item_id; + var name = this.ks_dashboard_data.ks_item_data[itemId].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), + }); + } + ksRenderChartColorOptions(e) { + var self = this; + if (!$(e.currentTarget).parent().hasClass('ks_date_filter_selected')) { + // FIXME : Correct this later. + var $parent = $(e.currentTarget).parent().parent(); + $parent.find('.ks_date_filter_selected').removeClass('ks_date_filter_selected') + $(e.currentTarget).parent().addClass('ks_date_filter_selected') + 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(function() { + self.ks_dashboard_data.ks_item_data[$parent.data().itemId]['ks_chart_item_color'] = e.target.dataset.chartColor; + $(self.main_body.el).find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove(); + + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + + }) + } + } + + + ksOnDashboardExportClick(ev){ + ev.preventDefault(); + var self= this; + var 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', + }); + }); + } + stoppropagation(ev){ +// ev.stopPropagation(); + this.ksAllowItemClick = false; + } + + ksOnDashboardImportClick(ev){ + ev.preventDefault(); + var self = this; + var 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.actionService.doAction(result) + }); + } + + _ksOnDnLayoutMenuSelect(ev){ + var selected_layout_id = $(ev.currentTarget).data('ks_layout_id'); + this.ksOnLayoutSelection(selected_layout_id); + } + + 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}); + }); + + +// this.ks_dashboard_data.ks_selected_board_id = layout_id; + $(self.header.el).find("#ks_dashboard_layout_dropdown_container .ks_layout_selected").removeClass("ks_layout_selected"); + $(self.header.el).find("li.ks_dashboard_layout_event[data-ks_layout_id='"+ layout_id + "']").addClass('ks_layout_selected'); + $(self.header.el).find("#ks_dn_layout_button span:first-child").text(selected_layout_name); + $(self.header.el).find(".ks_dashboard_top_menu .ks_dashboard_edit_layout").addClass("ks_hide"); + $(self.header.el).find(".ks_dashboard_top_menu .ks_am_content_element").addClass("ks_hide"); + + $(self.header.el).find(".ks_dashboard_layout_edit_mode_settings").removeClass("ks_hide"); + } + + _onKsSaveLayoutClick(){ + this.grid.setStatic(true) + var self = this; + // Have to save dashboard here + var dashboard_title = $('#ks_dashboard_title_input').val(); + if (dashboard_title != false && dashboard_title != 0 && dashboard_title !== self.ks_dashboard_data.name) { + self.ks_dashboard_data.name = dashboard_title; + var model = 'ks_dashboard_ninja.board'; + var rec_id = self.ks_dashboard_id; + + 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][0] = dashboard_title; + if (this.ks_dashboard_data.ks_selected_board_id !== 'ks_default'){ + model = 'ks_dashboard_ninja.child_board'; + rec_id = this.ks_dashboard_data.ks_selected_board_id; + } + } + var new_model = `web/dataset/call_kw/${model}/write` + this._rpc(new_model,{ + model: model, + method: 'write', + args: [rec_id, { + 'name': dashboard_title + }], + kwargs : {}, + }) + } + if (this.ks_dashboard_data.ks_item_data) self._ksSaveCurrentLayout(); + self._ksRenderActiveMode(); + } + + _onKsCancelLayoutClick(){ + var self = this; + // render page again + + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + + } + + _onKsCreateLayoutClick() { + var self = this; + self.grid.setStatic(true) + var dashboard_title = $('#ks_dashboard_title_input').val(); + if (dashboard_title ==="") { + self.call('notification', 'notify', { + message: "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; + + var grid_config = self.ks_get_current_gridstack_config(); + 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){ + var self = this; + var child_board_id = res_id.toString(); + self.ks_dashboard_data.ks_selected_board_id = child_board_id; + var 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); + } + + _ksRenderActiveMode(){ + var self = this + self.ks_mode = 'active'; + + if (self.grid && $('.grid-stack').data('gridstack')) { + $('.grid-stack').data('gridstack').disable(); + } + + if (self.ks_dashboard_data.ks_child_boards) { + var $layout_container = $(renderToElement('ks_dn_layout_container_new', { + ks_selected_board_id: self.ks_dashboard_data.ks_selected_board_id, + ks_child_boards: self.ks_dashboard_data.ks_child_boards, + ks_multi_layout: self.ks_dashboard_data.multi_layouts, + ks_dash_name: self.ks_dashboard_data.name, + self:self, + })); + $('#ks_dashboard_title .ks_am_element').replaceWith($layout_container); + $('#ks_dashboard_title_label').replaceWith($layout_container); + } else { + $('#ks_dashboard_title_label').text(self.ks_dashboard_data.name); + } + + $('#ks_dashboard_title_label').text(self.ks_dashboard_data.name); + + $('.ks_am_element').removeClass("ks_hide"); + $('.ks_em_element').addClass("ks_hide"); + $('.ks_dashboard_print_pdf').removeClass("ks_hide"); + if (self.ks_dashboard_data.ks_item_data) $('.ks_am_content_element').removeClass("ks_hide"); + + $(self.main_body.el).find('.ks_item_not_click').addClass('ks_item_click').removeClass('ks_item_not_click') + $(self.main_body.el).find('.ks_dashboard_item').addClass('ks_dashboard_item_header_hover') + $(self.main_body.el).find('.ks_dashboard_item_header').addClass('ks_dashboard_item_header_hover') + + $(self.main_body.el).find('.ks_dashboard_item_l2').addClass('ks_dashboard_item_header_hover') + $(self.main_body.el).find('.ks_dashboard_item_header_l2').addClass('ks_dashboard_item_header_hover') + + // For layout 5 + $(self.main_body.el).find('.ks_dashboard_item_l5').addClass('ks_dashboard_item_header_hover') + + + $(self.main_body.el).find('.ks_dashboard_item_button_container').addClass('ks_dashboard_item_header_hover'); + + $(self.header.el).find('.ks_dashboard_top_settings').removeClass("ks_hide") + $(self.header.el).find('.ks_dashboard_edit_mode_settings').addClass("ks_hide") + $(self.header.el).find("#ks_dashboard_layout_edit").removeClass("ks_hide") + $(self.header.el).find("#ks_import_item").removeClass("ks_hide") + + $(self.main_body.el).find('.ks_start_tv_dashboard').removeClass('ks_hide'); + $(self.main_body.el).find('.ks_chart_container').removeClass('ks_item_not_click ks_item_click'); + $(self.main_body.el).find('.ks_list_view_container').removeClass('ks_item_click'); + + + self.grid.commit(); + } + + 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.grid.setStatic(false); + self.ksAllowItemClick = false; + self._ksRenderEditMode(); + } + + _ksRenderEditMode(){ + var self = this; + self.ks_mode = 'edit'; + self.ks_remove_update_interval(); + + // Update the value of an input element with the ID 'ks_dashboard_title_input' + // using the current dashboard name + $('#ks_dashboard_title_input').val(self.ks_dashboard_data.name); + + // Hide and show certain elements based on the edit mode + $('.ks_am_element').addClass("ks_hide"); + $('.ks_em_element').removeClass("ks_hide"); + $('.ks_dashboard_print_pdf').addClass("ks_hide"); + + // Update classes for various dashboard elements to control their styling + $(self.main_body.el).find('.ks_item_click').addClass('ks_item_not_click').removeClass('ks_item_click'); + $(self.main_body.el).find('.ks_dashboard_item').removeClass('ks_dashboard_item_header_hover'); + $(self.main_body.el).find('.ks_dashboard_item_header').removeClass('ks_dashboard_item_header_hover'); + $(self.main_body.el).find('.ks_dashboard_item_l2').removeClass('ks_dashboard_item_header_hover'); + $(self.main_body.el).find('.ks_dashboard_item_header_l2').removeClass('ks_dashboard_item_header_hover'); + $(self.main_body.el).find('.ks_dashboard_item_l5').removeClass('ks_dashboard_item_header_hover'); + $(self.main_body.el).find('.ks_dashboard_item_button_container').removeClass('ks_dashboard_item_header_hover'); + +// $(self.header.el).find('.ks_dashboard_link').addClass("ks_hide") + $(self.header.el).find('.ks_dashboard_top_settings').addClass("ks_hide") + $(self.header.el).find('.ks_dashboard_edit_mode_settings').removeClass("ks_hide") + + // Hide elements related to TV dashboard and make certain elements not clickable + $(self.main_body.el).find('.ks_start_tv_dashboard').addClass('ks_hide'); + $(self.main_body.el).find('.ks_chart_container').addClass('ks_item_not_click'); + $(self.main_body.el).find('.ks_list_view_container').addClass('ks_item_not_click'); + + if (self.grid) { + self.grid.enable(); + } + } + + + onAddItemTypeClick(e) { + var self = this; + self.dialogService.add(FormViewDialog,{ + resModel: 'ks_dashboard_ninja.item', + context: { + 'ks_dashboard_id': self.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.actionService.currentController.jsId + self.actionService.restore(js_id) + $('body').removeClass('ks_dn_create_chart') + + }, + onRecordDiscarded:()=>{ + $('body').removeClass('ks_dn_create_chart') + } + }); + + } + + ksImportItemJson(e) { + 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.actionService.currentController.jsId + self.actionService.restore(js_id) + } + }); + }; + fileReader.readAsText($('.ks_input_import_item_button').prop('files')[0]); + } + + + ksOnDashboardSettingClick(ev){ + var self= this; + var dashboard_id = this.ks_dashboard_id; + var action = { + name: _t('ks_open_setting'), + 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.actionService.doAction(action) + } + + ksOnDashboardDeleteClick(ev){ + ev.preventDefault(); + var dashboard_id = this.ks_dashboard_id; + var self= this; + self.dialogService.add(ConfirmationDialog, { + body: _t("Are you sure you want to delete this 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: [self.ks_dashboard_id], + kwargs: {dashboard_id: dashboard_id} + }).then((result)=>{ + self.actionService.doAction(result) + }); + }, + }); + } + + ksOnDashboardCreateClick(ev){ + var self= this; + var 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', + } + self.actionService.doAction(action) + } + + ksOnDashboardDuplicateClick(ev){ + ev.preventDefault(); + var self= this; + var 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: [self.ks_dashboard_id], + kwargs: {} + }).then((result)=>{ + self.actionService.doAction(result) + }); + } + + onEditItemTypeClick(ev) { + this.ksAllowItemClick = false; + var self =this + if(ev.currentTarget.dataset.itemId){ + self.dialogService.add(FormViewDialog,{ + resModel: 'ks_dashboard_ninja.item', + resId : parseInt(ev.currentTarget.dataset.itemId), + context: { + 'form_view_ref': 'ks_dashboard_ninja.item_form_view', + 'form_view_initial_mode': 'edit', + 'ks_form_view' :true + }, + onRecordSaved:()=>{ + + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + $('body').removeClass('ks_dn_create_chart') + }, + onRecordDiscarded:()=>{ + $('body').removeClass('ks_dn_create_chart') + } + }); + } + + } + kscreateaiitem(ev){ + var self= this; + self.dialogService.add(FormViewDialog,{ + resModel: 'ks_dashboard_ninja.arti_int', + context: { + 'ks_dashboard_id': self.ks_dashboard_id, + 'ks_form_view' : true + }, + }); + } + kscreateaidashboard(ev){ + var self= this; + var 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.actionService.doAction(action) + } + ks_gen_ai_analysis(ev){ + var self = this; + 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)=>{ + if (!item.ks_ai_analysis){ + 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:item.ks_list_view_data?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 + }) + } + else{ + ks_rest_items.push(item) + } + + }); + 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?"), + 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){ + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + } + }); + } + }); + }else{ + self.notification.add(_t('Plese make few items to explain with AI'),{ + title:_t("Failed"), + type: 'warning', + }); + } + } + ks_switch_default_dashboard(ev){ + var self = this; + if (self.ks_dashboard_data.ks_ai_explain_dash){ + 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:{}, + }).then(function(result) { + var js_id = self.actionService.currentController.jsId + self.actionService.restore(js_id) + }); + } + } + async speak_once(ev,item){ + this.ksAllowItemClick = false; + ev.preventDefault() + var ks_audio = ev.currentTarget + $(document.querySelectorAll('audio')).each((index,item)=>{ + if ($(item).attr('src') && $(ks_audio).find('audio').attr('src') != $(item).attr('src')){ + item.pause() + $(item).parent().find('.fa.fa-volume-up').addClass('d-none'); + if (!$(item).parent().find(".fa-pause").length){ + $(item).parent().append(''); + } + + } + }) + if (!this.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('.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('.fa.fa-volume-up').addClass('d-none'); + $(ks_audio).append(''); + }else{ + $(ks_audio).find('span').addClass('d-none') + $(ks_audio).append('
') + this.ks_speeches.push(this._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('.spinner-grow').remove() + $(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() + this.ks_speeches.pop() + } + }.bind(this))) + return Promise.resolve(this.ks_speeches) + } + + } + } + +} + +KsDashboardNinja.components = { Ksdashboardtile, Ksdashboardlistview, Ksdashboardgraph, Ksdashboardkpiview, Ksdashboardtodo, DateTimePicker, DateTimeInput}; +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 this.super(...args); + 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) \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_date_picker.js b/ks_dashboard_ninja/static/src/js/ks_date_picker.js new file mode 100644 index 000000000..1fe77c5b3 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_date_picker.js @@ -0,0 +1,16 @@ +odoo.define("ks_dashboard_ninja.ks_date_picker", function(require) { + "use strict"; + var datepicker = require("web.datepicker"); + + datepicker.DateWidget.include({ + + _onDateTimePickerShow: function() { + this._super.apply(this, arguments); + + if (this.name === "ks_dashboard") { + window.removeEventListener('scroll', this._onScroll, true); + } + }, + }); + return datepicker; +}) \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_domain_fix.js b/ks_dashboard_ninja/static/src/js/ks_domain_fix.js new file mode 100644 index 000000000..b7fc1eccf --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_domain_fix.js @@ -0,0 +1,73 @@ +odoo.define('ks_dashboard_ninja.domain_fix', function(require) { + + "use strict"; + + var BasicModel = require('web.BasicModel'); + var BasicFields = require('web.basic_fields'); + var view_dialogs = require('web.view_dialogs'); + var core = require("web.core"); + var Domain = require('web.Domain'); + + var _t = core._t; + + // Whole Point of this file is to enable users to use %UID to calculate domain dynamically. + BasicModel.include({ + + _fetchSpecialDomain: function(record, fieldName, fieldInfo) { + var self = this; + var fieldName_temp = fieldName; + if (record._changes && record._changes[fieldName]) { + if (record._changes[fieldName].includes("%UID") || record._changes[fieldName].includes("%MYCOMPANY")) { + fieldName_temp = fieldName + '_temp'; + record._changes[fieldName_temp] = record._changes[fieldName] + while (record._changes[fieldName_temp].includes("%UID")){ + record._changes[fieldName_temp] = record._changes[fieldName_temp].replace('"%UID"', record.getContext().uid); + } + while (record._changes[fieldName_temp].includes("%MYCOMPANY")){ + record._changes[fieldName_temp] = record._changes[fieldName_temp].replace('"%MYCOMPANY"', this.getSession().user_context.allowed_company_ids[0]) + } + } + + } else if (record.data[fieldName] && (record.data[fieldName].includes("%UID") || record.data[fieldName].includes("%MYCOMPANY"))) { + fieldName_temp = fieldName + '_temp'; + record.data[fieldName_temp] = record.data[fieldName]; + + while (record.data[fieldName_temp].includes("%UID")){ + record.data[fieldName_temp] = record.data[fieldName_temp].replace('"%UID"', record.getContext().uid); + } + while (record.data[fieldName_temp].includes("%MYCOMPANY")){ + record.data[fieldName_temp] = record.data[fieldName_temp].replace('"%MYCOMPANY"', this.getSession().user_context.allowed_company_ids[0]) + } + } + return this._super(record,fieldName_temp,fieldInfo); + }, + + }); + + BasicFields.FieldDomain.include({ + + _onShowSelectionButtonClick: function(e) { + if (this.value && (this.value.includes("%MYCOMPANY") || this.value && this.value.includes("%UID")) ){ + var temp_value = this.value; + while(temp_value.includes("%MYCOMPANY")){ + var temp_value = temp_value.includes("%MYCOMPANY") ? temp_value.replace('"%MYCOMPANY"', this.getSession().user_context.allowed_company_ids[0]): temp_value; + } + while(temp_value.includes("%UID")){ + temp_value = temp_value.includes("%UID") ? temp_value.replace('"%UID"', this.record.getContext().uid): temp_value; + } + e.preventDefault(); + new view_dialogs.SelectCreateDialog(this, { + title: _t("Selected records"), + res_model: this._domainModel, + domain: temp_value, + no_create: true, + readonly: true, + disable_multiple_selection: true, + }).open(); + }else{ + this._super.apply(this, arguments); + } + }, + }); + +}); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_filter_props.js b/ks_dashboard_ninja/static/src/js/ks_filter_props.js new file mode 100644 index 000000000..ebc406b74 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_filter_props.js @@ -0,0 +1,533 @@ +odoo.define('ks_dashboard_ninja.ks_dashboard_filter', function (require) { +"use strict"; + +var KsFilterProps = require('ks_dashboard_ninja.ks_dashboard'); +var core = require('web.core'); +var QWeb = core.qweb; +var datepicker = require("web.datepicker"); +const { FIELD_OPERATORS, FIELD_TYPES } = require('web.searchUtils'); +const field_utils = require('web.field_utils'); + + +return KsFilterProps.include({ + + events: _.extend({}, KsFilterProps.prototype.events, { + 'hide.bs.dropdown .ks_dn_selection_box > div': 'onKsDnFilterBoxContainerHide', + 'click .dn_filter_click_event_selector': 'onKsDnDynamicFilterSelect', + 'click .ks_custom_filter_add_condition': 'ksOnCustomFilterConditionAdd', + 'click .ks_custom_filter_section_delete': 'ksOnCustomFilterConditionRemove', + 'click .ks_dn_filter_apply': 'ksOnCustomFilterApply', + 'click .ks_dn_filter_remove_event': 'ksOnRemoveFilterFromSearchPanel', + 'change .ks_custom_filter_field_selector': 'ksOnCustomFilterFieldSelect', + 'change .ks_custom_filter_field_selector': 'ksOnCustomFilterFieldSelect', + 'change .ks_operator_option_selector': 'ksOnCustomFilterOperatorSelect', + 'change .ks_operator_option_selector': 'ksOnCustomFilterOperatorSelect', + }), + + init: function(){ + this._super.apply(this, arguments); + this.ksCustomFilterData = { + OPERATORS : FIELD_OPERATORS, + FIELD_TYPES : FIELD_TYPES, + DECIMAL_POINT : 2, + } + }, + + onKsDnFilterBoxContainerHide: function(ev){ + if(ev.clickEvent && ev.clickEvent.target && $(ev.clickEvent.target).parents(".ks_dn_filter_dropdown_container").length) { + return false; + } + }, + + onKsDnDynamicFilterSelect: function(ev){ + var self = this; + if($(ev.currentTarget).hasClass('dn_dynamic_filter_selected')){ + self._ksRemoveDynamicFilter(ev.currentTarget.dataset['filterId']); + $(ev.currentTarget).removeClass('dn_dynamic_filter_selected'); + } else { + self._ksAppendDynamicFilter(ev.currentTarget.dataset['filterId']); + $(ev.currentTarget).addClass('dn_dynamic_filter_selected'); + } + }, + + _ksAppendDynamicFilter: function(filterId){ + // Update predomain data -> Add into Domain Index -> Add or remove class + this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].active = true; + + var action = 'add_dynamic_filter'; + var categ = this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].categ; + var params = { + 'model': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model, + 'model_name': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model_name, + } + this._ksUpdateAddDomainIndexData(action, categ, params); + }, + + _ksRemoveDynamicFilter: function(filterId){ + // Update predomain data -> Remove from Domain Index -> Add or remove class + this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].active = false; + + var action = 'remove_dynamic_filter'; + var categ = this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].categ; + var params = { + 'model': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model, + 'model_name': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model_name, + } + this._ksUpdateRemoveDomainIndexData(action, categ, params); + }, + + _ksUpdateAddDomainIndexData : function(action, categ, params){ + // Update Domain Index: Add or Remove model related data, Update its domain, item ids + // Fetch records for the effected items + // Re-render Search box of this name if the value is add + var self = this; + var model = params['model'] || false; + var model_name = params['model_name'] || ''; + $(".ks_dn_filter_applied_container").removeClass('ks_hide'); + + var filters_to_update = _(this.ks_dashboard_data.ks_dashboard_pre_domain_filter).values().filter((x)=>{return x.active === true && x.categ === categ}); + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + if (domain_data) { + var domain_index = _(domain_data.ks_domain_index_data).find((x)=>{return x.categ === categ}); + if (domain_index) { + domain_index['domain'] = []; + domain_index['label'] = []; + _(filters_to_update).each((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }) + } else { + domain_index = { + categ: categ, + domain: [], + label: [], + model: model, + } + _(filters_to_update).each((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }) + domain_data.ks_domain_index_data.push(domain_index); + } + + var $filter_container = $(QWeb.render('ks_dn_filter_section_container_template', { + ks_domain_data: domain_data, + ks_model: model, + })); + $('.ks_dn_filter_section_container[data-ks-model-selector="'+ model + '"]').replaceWith($filter_container); + + } else { + var domain_index = { + categ: categ, + domain: [], + label: [], + model: model, + } + _(filters_to_update).each((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }) + domain_data = { + 'domain': [], + 'model_name': model_name, + 'item_ids': self.ks_dashboard_data.ks_model_item_relation[model], + 'ks_domain_index_data': [domain_index], + } + self.ks_dashboard_data.ks_dashboard_domain_data[model] = domain_data; + var $filter_container = $(QWeb.render('ks_dn_filter_section_container_template', { + ks_domain_data: domain_data, + ks_model: model, + })); + $('.ks_dn_filter_applied_container').prepend($filter_container); + } + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + + _(domain_data['item_ids']).each((x)=>{self.ksFetchUpdateItem(x)}); + }, + + _ksUpdateRemoveDomainIndexData: function(action, categ, params){ + var self = this; + var model = params['model'] || false; + var model_name = params['model_name'] || ''; + var filters_to_update = _(this.ks_dashboard_data.ks_dashboard_pre_domain_filter).values().filter((x)=>{return x.active === true && x.categ === categ}); + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + var domain_index = _(domain_data.ks_domain_index_data).find((x)=>{return x.categ === categ}); + + if (filters_to_update.length<1) { + if (domain_data.ks_domain_index_data.length>1){ + domain_data.ks_domain_index_data.splice(domain_data.ks_domain_index_data.indexOf(domain_index),1); + $('.o_searchview_facet[data-ks-categ="'+ categ + '"]').remove(); + }else { + $('.ks_dn_filter_section_container[data-ks-model-selector="'+ model + '"]').remove(); + delete self.ks_dashboard_data.ks_dashboard_domain_data[model]; + if(!_(self.ks_dashboard_data.ks_dashboard_domain_data).keys().length){ + $(".ks_dn_filter_applied_container").addClass('ks_hide'); + } + } + } else{ + domain_index['domain'] = []; + domain_index['label'] = []; + _(filters_to_update).each((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }) + var $filter_container = $(QWeb.render('ks_dn_filter_section_container_template', { + ks_domain_data: domain_data, + ks_model: model, + })); + $('.ks_dn_filter_section_container[data-ks-model-selector="'+ model + '"]').replaceWith($filter_container); + } + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + _(domain_data['item_ids']).each((x)=>{self.ksFetchUpdateItem(x)}); + }, + + _ksMakeDomainFromDomainIndex: function(ks_domain_index_data){ + var domain = []; + _(ks_domain_index_data).each((x)=>{ + if (domain.length>0) domain.unshift('&'); + domain = domain.concat((x['domain'])); + }) + return domain; + }, + + ksGetParamsForItemFetch: function(item_id) { + var self = this; + var model1 = self.ks_dashboard_data.ks_item_model_relation[item_id][0]; + var model2 = self.ks_dashboard_data.ks_item_model_relation[item_id][1]; + + if(model1 in self.ks_dashboard_data.ks_model_item_relation) { + if (self.ks_dashboard_data.ks_model_item_relation[model1].indexOf(item_id)<0) + self.ks_dashboard_data.ks_model_item_relation[model1].push(item_id); + }else { + self.ks_dashboard_data.ks_model_item_relation[model1] = [item_id]; + } + + if(model2 in self.ks_dashboard_data.ks_model_item_relation) { + if (self.ks_dashboard_data.ks_model_item_relation[model2].indexOf(item_id)<0) + self.ks_dashboard_data.ks_model_item_relation[model2].push(item_id); + }else { + self.ks_dashboard_data.ks_model_item_relation[model2] = [item_id]; + } + + var ks_domain_1 = self.ks_dashboard_data.ks_dashboard_domain_data[model1] && self.ks_dashboard_data.ks_dashboard_domain_data[model1]['domain'] || []; + var ks_domain_2 = self.ks_dashboard_data.ks_dashboard_domain_data[model2] && self.ks_dashboard_data.ks_dashboard_domain_data[model2]['domain'] || []; + + return { + ks_domain_1: ks_domain_1, + ks_domain_2: ks_domain_2, + } + }, + + ks_fetch_items_data: function(){ + var self = this; + return this._super.apply(this, arguments).then(function(){ + if (self.ks_dashboard_data.ks_dashboard_domain_data) self.ks_init_domain_data_index(); + }); + }, + + ks_init_domain_data_index: function(){ + var self = this; + // TODO: Make domain data index from backend : loop wasted + var temp_data = {}; + var to_insert = _(this.ks_dashboard_data.ks_dashboard_pre_domain_filter).values().filter((x)=>{ + return x.type==='filter' && x.active && self.ks_dashboard_data.ks_dashboard_domain_data[x.model].ks_domain_index_data.length === 0 + }); + _(to_insert).each((x)=>{ + if(x['categ'] in temp_data) { + temp_data[x['categ']]['domain']= temp_data[x['categ']]['domain'].concat(x['domain']); + temp_data[x['categ']]['label']= temp_data[x['categ']]['label'].concat(x['name']); + } else { + temp_data[x['categ']] = {'domain': x['domain'], 'label': [x['name']], 'categ': x['categ'], 'model': x['model']}; + } + }) + _(temp_data).values().forEach((x)=>{ + self.ks_dashboard_data.ks_dashboard_domain_data[x.model].ks_domain_index_data.push(x); + }) + }, + + // Custom Filter Events and Functions ------------------------------------------------------------------- + + ksRenderDashboard: function(){ + var self = this; + this._super.apply(this, arguments); + var show_remove_option = false; + if (Object.values(self.ks_dashboard_data.ks_dashboard_custom_domain_filter).length>0) self.ks_render_custom_filter(show_remove_option); + }, + + ks_render_custom_filter: function(show_remove_option){ + var $container = $(QWeb.render('ks_dn_custom_filter_input_container', { + ks_dashboard_custom_domain_filter: Object.values(this.ks_dashboard_data.ks_dashboard_custom_domain_filter), + show_remove_option: show_remove_option, + })); + + var first_field_select = Object.values(this.ks_dashboard_data.ks_dashboard_custom_domain_filter)[0] + var field_type = first_field_select.field_type; + var operators = this.ksCustomFilterData.OPERATORS[this.ksCustomFilterData.FIELD_TYPES[field_type]]; + var operator_type = operators[0]; + var $operator_input = $(QWeb.render('ks_dn_custom_domain_input_operator', { + operators: operators, + })); + $container.append($operator_input); + + var $value_input = this._ksRenderCustomFilterInputSection(operator_type, this.ksCustomFilterData.FIELD_TYPES[field_type], first_field_select.special_data) + if ($value_input) $container.append($value_input); + + $("#ks_dn_custom_filters_container").append($container); + }, + + _ksRenderCustomFilterInputSection: function(operator_type, field_type, special_data){ + var $value_input; + switch (field_type) { + case 'boolean': + return false; + break; + case 'selection': + if ('value' in operator_type) return false; + else $value_input = $(QWeb.render('ks_dn_custom_domain_input_selection', { + selection_input: special_data['select_options'] || [], + })); + break; + case 'date': + case 'datetime': + if ('value' in operator_type) return false; + $value_input = this._ksRenderDateTimeFilterInput(operator_type, field_type); + break; + case 'char': + case 'id': + case 'number' : + if ('value' in operator_type) return false; + else $value_input = $(QWeb.render('ks_dn_custom_domain_input_text', {})); + break; + default: + return; + } + return $value_input; + }, + + _ksRenderDateTimeFilterInput: function(operator, field_type){ + var $value_container = $(QWeb.render('ks_dn_custom_domain_input_date')); + switch(field_type) { + case 'date': + var $date_time_picker = new(datepicker.DateWidget)(this); + $date_time_picker.appendTo($value_container).then((function() { + $date_time_picker.$el.addClass("ks_dn_filter_first_date_time_widget o_input"); + $date_time_picker.setValue(moment()); + }).bind(this)); + + if (operator.symbol === 'between') { + var $date_time_picker_2 = new(datepicker.DateWidget)(this); + $date_time_picker_2.appendTo($value_container).then((function() { + $date_time_picker_2.$el.addClass("ks_dn_filter_second_date_time_widget o_input"); + $date_time_picker_2.setValue(moment()); + }).bind(this)); + } + break; + case 'datetime': + var $date_time_picker = new(datepicker.DateTimeWidget)(this); + $date_time_picker.appendTo($value_container).then((function() { + $date_time_picker.$el.addClass("ks_dn_filter_first_date_time_widget o_input"); + $date_time_picker.setValue(moment('00:00:00', 'hh:mm:ss')); + }).bind(this)); + + if (operator.symbol === 'between') { + var $date_time_picker_2 = new(datepicker.DateTimeWidget)(this); + $date_time_picker_2.appendTo($value_container).then((function() { + $date_time_picker_2.$el.addClass("ks_dn_filter_second_date_time_widget o_input"); + $date_time_picker_2.setValue(moment('23:59:59', 'hh:mm:ss')); + }).bind(this)); + } + break; + } + + return $value_container; + }, + + ksOnCustomFilterConditionAdd: function(){ + var show_remove_option = true; + this.ks_render_custom_filter(show_remove_option); + }, + + ksOnCustomFilterConditionRemove: function(ev){ + ev.stopPropagation(); + $(ev.currentTarget.parentElement).remove(); + }, + + ksOnCustomFilterFieldSelect: function(ev){ + var $parent_container = $(ev.currentTarget.parentElement); + $parent_container.find('.ks_operator_option_selector').remove(); + $parent_container.find('.o_generator_menu_value').remove(); + + var field_id = ev.currentTarget.value; + var field_select = this.ks_dashboard_data.ks_dashboard_custom_domain_filter[field_id]; + var field_type = field_select.field_type; + var operators = this.ksCustomFilterData.OPERATORS[this.ksCustomFilterData.FIELD_TYPES[field_type]]; + var operator_type = operators[0]; + var $operator_input = $(QWeb.render('ks_dn_custom_domain_input_operator', { + operators: operators, + })); + + $parent_container.append($operator_input); + var $value_input = this._ksRenderCustomFilterInputSection(operator_type, this.ksCustomFilterData.FIELD_TYPES[field_type], field_select.special_data) + if ($value_input) $parent_container.append($value_input); + }, + + ksOnCustomFilterOperatorSelect: function(ev){ + var $parent_container = $(ev.currentTarget.parentElement); + var operator_symbol = ev.currentTarget.value; + var field_id = $parent_container.find('.ks_custom_filter_field_selector').val(); + var field_select = this.ks_dashboard_data.ks_dashboard_custom_domain_filter[field_id]; + var field_type = field_select.field_type; + var operator_type = this.ksCustomFilterData.OPERATORS[this.ksCustomFilterData.FIELD_TYPES[field_type]][ev.currentTarget.selectedIndex]; + + $parent_container.find('.o_generator_menu_value').remove(); + var $value_input = this._ksRenderCustomFilterInputSection(operator_type, this.ksCustomFilterData.FIELD_TYPES[field_type], field_select.special_data) + if ($value_input) $parent_container.append($value_input); + }, + + ksOnCustomFilterApply: function(){ + var model_domain = {}; + $('.ks_dn_custom_filter_input_container_section').each((index, filter_container) => { + var field_id = $(filter_container).find('.ks_custom_filter_field_selector').val(); + var field_select = this.ks_dashboard_data.ks_dashboard_custom_domain_filter[field_id]; + var field_type = field_select.field_type; + var domainValue = []; + var domainArray = []; + var operator = this.ksCustomFilterData.OPERATORS[this.ksCustomFilterData.FIELD_TYPES[field_type]][$(filter_container).find('.ks_operator_option_selector').prop('selectedIndex')]; + var label = field_select.name + ' ' + operator.description; + if ('value' in operator){ + domainValue = [operator.value]; + } else if (['date', 'datetime'].includes(field_type)) { + var dateValue = []; + $(filter_container).find(".o_generator_menu_value .o_datepicker").each((index, $input_val) => { + var a = $($input_val).find("input").val();; + var b = field_utils.parse[field_type](a, { field_type }, { timezone: true }); + var c = field_utils.format[field_type](b, { field_type }, { timezone: true }); + domainValue.push(b.toJSON()); + dateValue.push(c); + }); + label = label +' ' + dateValue.join(" and " ); + } else if (field_type === 'selection') { + domainValue = [$(filter_container).find(".o_generator_menu_value").val()] + label = label + ' ' + $(filter_container).find(".o_generator_menu_value").val(); + } + else { + domainValue = [$(filter_container).find(".o_generator_menu_value input").val()] + label = label +' ' + $(filter_container).find(".o_generator_menu_value input").val(); + } + + if (operator.symbol === 'between') { + domainArray.push( + [field_select.field_name, '>=', domainValue[0]], + [field_select.field_name, '<=', domainValue[1]] + ); + domainArray.unshift('&'); + } else { + domainArray.push([field_select.field_name, operator.symbol, domainValue[0]]); + } + + if(field_select.model in model_domain){ + model_domain[field_select.model]['domain'] = model_domain[field_select.model]['domain'].concat(domainArray); + model_domain[field_select.model]['domain'].unshift('|'); + model_domain[field_select.model]['label'] = model_domain[field_select.model]['label'] + ' or ' + label; + } else { + model_domain[field_select.model] = { + 'domain': domainArray, + 'label': label, + 'model_name': field_select.model_name, + } + } + }); + this._ksAddCustomDomain(model_domain); + }, + + _ksAddCustomDomain: function(model_domain){ + var self = this; + $(".ks_dn_filter_applied_container").removeClass('ks_hide'); + _(model_domain).each((val,model)=>{ + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + var domain_index = { + categ: false, + domain: val['domain'], + label: [val['label']], + model: model, + } + + if (domain_data) { + domain_data.ks_domain_index_data.push(domain_index); + var $filter_container = $(QWeb.render('ks_dn_filter_section_container_template', { + ks_domain_data: domain_data, + ks_model: model, + })); + $('.ks_dn_filter_section_container[data-ks-model-selector="'+ model + '"]').replaceWith($filter_container); + } else { + domain_data = { + 'domain': [], + 'model_name': val.model_name, + 'item_ids': self.ks_dashboard_data.ks_model_item_relation[model], + 'ks_domain_index_data': [domain_index], + } + self.ks_dashboard_data.ks_dashboard_domain_data[model] = domain_data; + var $filter_container = $(QWeb.render('ks_dn_filter_section_container_template', { + ks_domain_data: domain_data, + ks_model: model, + })); + $('.ks_dn_filter_applied_container').prepend($filter_container); + } + + $("#ks_dn_custom_filters_container").empty(); + var show_remove_option = false; + self.ks_render_custom_filter(show_remove_option); + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + _(domain_data['item_ids']).each((x)=>{self.ksFetchUpdateItem(x)}); + }) + }, + + ksOnRemoveFilterFromSearchPanel: function(ev){ + var self = this; + ev.stopPropagation(); + var $search_section = $(ev.currentTarget).parent(); + var model = $search_section.data('ksModel'); + if ($search_section.data('ksCateg')){ + var categ = $search_section.data('ksCateg'); + var action = 'remove_dynamic_filter'; + var $selected_pre_define_filter = $(".dn_dynamic_filter_selected.dn_filter_click_event_selector[data-ks-categ='"+ categ +"']"); + $selected_pre_define_filter.removeClass("dn_dynamic_filter_selected"); + _($selected_pre_define_filter).each((x,y)=>{ + var filter_id = $(x).data('filterId'); + self.ks_dashboard_data.ks_dashboard_pre_domain_filter[filter_id].active = false; + }) + var params = { + 'model': model, + 'model_name': $search_section.data('ksModelName'), + } + this._ksUpdateRemoveDomainIndexData(action, categ, params); + } else { + var index = $search_section.index(); + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + domain_data.ks_domain_index_data.splice(index, 1); + + if (domain_data.ks_domain_index_data.length === 0) { + $('.ks_dn_filter_section_container[data-ks-model-selector="'+ model + '"]').remove(); + delete self.ks_dashboard_data.ks_dashboard_domain_data[model]; + if(!_(self.ks_dashboard_data.ks_dashboard_domain_data).keys().length){ + $(".ks_dn_filter_applied_container").addClass('ks_hide'); + } + } else { + $search_section.remove(); + } + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + _(domain_data['item_ids']).each((x)=>{self.ksFetchUpdateItem(x)}); + } + }, + +}) + +}); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_filter_props_new.js b/ks_dashboard_ninja/static/src/js/ks_filter_props_new.js new file mode 100644 index 000000000..51a8abc07 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_filter_props_new.js @@ -0,0 +1,597 @@ +/** @odoo-module */ + +import { patch } from "@web/core/utils/patch"; +import {KsDashboardNinja} from "@ks_dashboard_ninja/js/ks_dashboard_ninja_new"; +import { _t } from "@web/core/l10n/translation"; +import { renderToElement,renderToString,renderToFragment } from "@web/core/utils/render"; +import { isBrowserChrome, isMobileOS } from "@web/core/browser/feature_detection"; +import { Ksdashboardtile } from '@ks_dashboard_ninja/components/ks_dashboard_tile_view/ks_dashboard_tile'; +import { getDomainDisplayedOperators } from "@web/core/domain_selector/domain_selector_operator_editor"; +import { getOperatorLabel } from "@web/core/tree_editor/tree_editor_operator_editor"; +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 { serializeDateTime, serializeDate } from "@web/core/l10n/dates"; + +const ks_field_type = { + binary: "binary", + boolean: "boolean", + char: "char", + date: "date", + datetime: "datetime", + float: "number", + html: "char", + id: "id", + integer: "number", + many2many: "char", + many2one:"char", + monetary: "number", + one2many: "char", + selection: "selection", + text: "char" +} + + + +patch(KsDashboardNinja.prototype,{ + ks_fetch_items_data(){ + var self = this; + return super.ks_fetch_items_data().then(function(){ + if (self.ks_dashboard_data.ks_dashboard_domain_data) self.ks_init_domain_data_index(); + }); + }, + + ks_init_domain_data_index(){ + var self = this; + // TODO: Make domain data index from backend : loop wasted + var temp_data = {}; + var to_insert = Object.values(this.ks_dashboard_data.ks_dashboard_pre_domain_filter).filter((x)=>{ + return x.type==='filter' && x.active && self.ks_dashboard_data.ks_dashboard_domain_data[x.model].ks_domain_index_data.length === 0 + }); + (to_insert).forEach((x)=>{ + if(x['categ'] in temp_data) { + temp_data[x['categ']]['domain']= temp_data[x['categ']]['domain'].concat(x['domain']); + temp_data[x['categ']]['label']= temp_data[x['categ']]['label'].concat(x['name']); + } else { + temp_data[x['categ']] = {'domain': x['domain'], 'label': [x['name']], 'categ': x['categ'], 'model': x['model']}; + } + }) + Object.values(temp_data).forEach((x)=>{ + self.ks_dashboard_data.ks_dashboard_domain_data[x.model].ks_domain_index_data.push(x); + }) + }, + onKsDnDynamicFilterSelect(ev){ + var self = this; + if($(ev.currentTarget).hasClass('dn_dynamic_filter_selected')){ + self._ksRemoveDynamicFilter(ev.currentTarget.dataset['filterId']); + $(ev.currentTarget).removeClass('dn_dynamic_filter_selected'); + } else { + self._ksAppendDynamicFilter(ev.currentTarget.dataset['filterId']); + $(ev.currentTarget).addClass('dn_dynamic_filter_selected'); + } + var storedData = this.getObjectFromCookie('FilterOrderData' + self.ks_dashboard_id); + if(storedData !== null ){ + this.eraseCookie('FilterOrderData' + self.ks_dashboard_id); + } + if(Object.keys(self.ks_dashboard_data.ks_dashboard_domain_data).length !==0){ + this.setObjectInCookie('FilterOrderData' + self.ks_dashboard_id, self.ks_dashboard_data.ks_dashboard_domain_data, 1); + } + }, + + _ksAppendDynamicFilter(filterId){ + // Update predomain data -> Add into Domain Index -> Add or remove class + this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].active = true; + + var action = 'add_dynamic_filter'; + var categ = this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].categ; + var params = { + 'model': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model, + 'model_name': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model_name, + } + this._ksUpdateAddDomainIndexData(action, categ, params); + }, + + _ksRemoveDynamicFilter(filterId){ + // Update predomain data -> Remove from Domain Index -> Add or remove class + this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].active = false; + + var action = 'remove_dynamic_filter'; + var categ = this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].categ; + var params = { + 'model': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model, + 'model_name': this.ks_dashboard_data.ks_dashboard_pre_domain_filter[filterId].model_name, + } + this._ksUpdateRemoveDomainIndexData(action, categ, params); + }, + + _ksUpdateAddDomainIndexData(action, categ, params){ + // Update Domain Index: Add or Remove model related data, Update its domain, item ids + // Fetch records for the effected items + // Re-render Search box of this name if the value is add + var self = this; + var model = params['model'] || false; + var model_name = params['model_name'] || ''; + $(".ks_dn_filter_applied_container").removeClass('ks_hide'); + + var filters_to_update = Object.values(this.ks_dashboard_data.ks_dashboard_pre_domain_filter).filter((x)=>{return x.active === true && x.categ === categ}); + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + if (domain_data) { + var domain_index = (domain_data.ks_domain_index_data).find((x)=>{return x.categ === categ}); + if (domain_index) { + domain_index['domain'] = []; + domain_index['label'] = []; + (filters_to_update).forEach((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }) + } else { + domain_index = { + categ: categ, + domain: [], + label: [], + model: model, + }; + filters_to_update.forEach((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }); + domain_data.ks_domain_index_data.push(domain_index); + } + + } else { + var domain_index = { + categ: categ, + domain: [], + label: [], + model: model, + }; + filters_to_update.forEach((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }); + domain_data = { + 'domain': [], + 'model_name': model_name, + 'item_ids': self.ks_dashboard_data.ks_model_item_relation[model], + 'ks_domain_index_data': [domain_index], + }; + self.ks_dashboard_data.ks_dashboard_domain_data[model] = domain_data; + } + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + self.state.pre_defined_filter = {...domain_data} + self.state.ksDateFilterSelection = 'none' + self.state.custom_filter = {} + }, + + _ksUpdateRemoveDomainIndexData(action, categ, params){ + var self = this; + var model = params['model'] || false; + var model_name = params['model_name'] || ''; + var filters_to_update = Object.values(this.ks_dashboard_data.ks_dashboard_pre_domain_filter).filter((x)=>{return x.active === true && x.categ === categ}); + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + var domain_index = (domain_data.ks_domain_index_data).find((x)=>{return x.categ === categ}); + + if (filters_to_update.length<1) { + if (domain_data.ks_domain_index_data.length>1){ + domain_data.ks_domain_index_data.splice(domain_data.ks_domain_index_data.indexOf(domain_index),1); +// $('.o_searchview_facet[data-ks-categ="'+ categ + '"]').remove(); + }else { + $('.ks_dn_filter_section_container[data-ks-model-selector="'+ model + '"]').remove(); + delete self.ks_dashboard_data.ks_dashboard_domain_data[model]; + if(!Object.keys(self.ks_dashboard_data.ks_dashboard_domain_data).length){ + $(".ks_dn_filter_applied_container").addClass('ks_hide'); + } + } + } else{ + domain_index['domain'] = []; + domain_index['label'] = []; + (filters_to_update).forEach((x)=>{ + if (domain_index['domain'].length>0) domain_index['domain'].unshift('|'); + domain_index['domain'] = domain_index['domain'].concat(x['domain']); + domain_index['label'] = domain_index['label'].concat(x['name']); + }) + } + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + domain_data['ks_remove'] = true + self.state.pre_defined_filter = {...domain_data} + if(domain_data['domain'].length != 0){ + var storedData = this.getObjectFromCookie('FilterOrderData' + self.ks_dashboard_id); + if(storedData !== null ){ + this.eraseCookie('FilterOrderData' + self.ks_dashboard_id); + } + if(Object.keys(self.ks_dashboard_data.ks_dashboard_domain_data).length !==0){ + this.setObjectInCookie('FilterOrderData' + self.ks_dashboard_id, self.ks_dashboard_data.ks_dashboard_domain_data, 1); + } + }else{ + var storedData = this.getObjectFromCookie('FilterOrderData' + self.ks_dashboard_id); + if(storedData){ + this.eraseCookie('FilterOrderData' + self.ks_dashboard_id); + } + } + self.state.ksDateFilterSelection = 'none' + self.state.custom_filter = {} + }, + + _ksMakeDomainFromDomainIndex(ks_domain_index_data){ + var domain = []; + (ks_domain_index_data).forEach((x)=>{ + if (domain.length>0) domain.unshift('&'); + domain = domain.concat((x['domain'])); + }) + return domain; + }, + ksOnRemoveFilterFromSearchPanel(ev){ + var self = this; + ev.stopPropagation(); + var $search_section = $(ev.currentTarget).parent(); + var model = $search_section.attr('ksmodel'); + if ($search_section.attr('kscateg') != '0'){ + var categ = $search_section.attr('kscateg'); + var action = 'remove_dynamic_filter'; + var $selected_pre_define_filter = $(".dn_dynamic_filter_selected.dn_filter_click_event_selector[data-ks-categ='"+ categ +"']"); + $selected_pre_define_filter.removeClass("dn_dynamic_filter_selected"); + ($selected_pre_define_filter).toArray().forEach((x)=>{ + var filter_id = $(x).data('filterId'); + self.ks_dashboard_data.ks_dashboard_pre_domain_filter[filter_id].active = false; + }) + var params = { + 'model': model, + 'model_name': $search_section.attr('modelName'), + } + this._ksUpdateRemoveDomainIndexData(action, categ, params); + } else { + var index = $search_section.index(); + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + domain_data.ks_domain_index_data.splice(index, 1); + + if (domain_data.ks_domain_index_data.length === 0) { + $('.ks_dn_filter_section_container[data-ks-model-selector="'+ model + '"]').remove(); + delete self.ks_dashboard_data.ks_dashboard_domain_data[model]; + if(!Object.keys(self.ks_dashboard_data.ks_dashboard_domain_data).length){ + $(".ks_dn_filter_applied_container").addClass('ks_hide'); + } + } +// } else { +// $search_section.remove(); +// } + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + domain_data['ks_remove'] = true + self.state.pre_defined_filter = {} + self.state.ksDateFilterSelection = 'none' + self.state.custom_filter = {...domain_data} + if(domain_data['domain'].length != 0){ + var storedData = this.getObjectFromCookie('FilterOrderData' + self.ks_dashboard_id); + if(storedData !== null ){ + this.eraseCookie('FilterOrderData' + self.ks_dashboard_id); + } + this.setObjectInCookie('FilterOrderData' + self.ks_dashboard_id, self.ks_dashboard_data.ks_dashboard_domain_data, 1); + }else{ + var storedData = this.getObjectFromCookie('FilterOrderData' + self.ks_dashboard_id); + if(storedData){ + this.eraseCookie('FilterOrderData' + self.ks_dashboard_id); + } + } + + } + }, + + ksGetParamsForItemFetch(item_id) { + var self = this; + var model1 = self.ks_dashboard_data.ks_item_model_relation[item_id][0]; + var model2 = self.ks_dashboard_data.ks_item_model_relation[item_id][1]; + + if(model1 in self.ks_dashboard_data.ks_model_item_relation) { + if (self.ks_dashboard_data.ks_model_item_relation[model1].indexOf(item_id)<0) + self.ks_dashboard_data.ks_model_item_relation[model1].push(item_id); + }else { + self.ks_dashboard_data.ks_model_item_relation[model1] = [item_id]; + } + + if(model2 in self.ks_dashboard_data.ks_model_item_relation) { + if (self.ks_dashboard_data.ks_model_item_relation[model2].indexOf(item_id)<0) + self.ks_dashboard_data.ks_model_item_relation[model2].push(item_id); + }else { + self.ks_dashboard_data.ks_model_item_relation[model2] = [item_id]; + } + + var ks_domain_1 = self.ks_dashboard_data.ks_dashboard_domain_data[model1] && self.ks_dashboard_data.ks_dashboard_domain_data[model1]['domain'] || []; + var ks_domain_2 = self.ks_dashboard_data.ks_dashboard_domain_data[model2] && self.ks_dashboard_data.ks_dashboard_domain_data[model2]['domain'] || []; + + return { + ks_domain_1: ks_domain_1, + ks_domain_2: ks_domain_2, + } + }, + + ksRenderDashboard(){ + var self = this; + super.ksRenderDashboard(); + var show_remove_option = false; + if (Object.values(self.ks_dashboard_data.ks_dashboard_custom_domain_filter).length>0) self.ks_render_custom_filter(show_remove_option); + }, + ks_render_custom_filter(show_remove_option){ + var self = this; + var $container = $(renderToElement('ks_dn_custom_filter_input_container', { + ks_dashboard_custom_domain_filter: Object.values(this.ks_dashboard_data.ks_dashboard_custom_domain_filter), + show_remove_option: show_remove_option, + self: self + + })); + + var first_field_select = Object.values(this.ks_dashboard_data.ks_dashboard_custom_domain_filter)[0] + var field_type = first_field_select.type; + var ks_operators = getDomainDisplayedOperators(first_field_select); + var operatorsinfo = ks_operators.map((x)=> getOperatorLabel(x)); + this.operators = ks_operators.map((val,index)=>{ + return{ + 'symbol': val, + 'description': operatorsinfo[index] + } + + }) + + var operator_type = this.operators[0]; + var $operator_input = $(renderToElement('ks_dn_custom_domain_input_operator', { + operators: this.operators, + self:self + })); + $container.append($operator_input); + + var $value_input = this._ksRenderCustomFilterInputSection(operator_type, ks_field_type[field_type], first_field_select.special_data) + if ($value_input) $container.append($value_input); + + $("#ks_dn_custom_filters_container").append($container); + }, + _ksRenderCustomFilterInputSection(operator_type, field_type, special_data){ + var $value_input; + switch (field_type) { + case 'boolean': + return false; + break; + case 'selection': + if (!operator_type) return false; + else $value_input = $(renderToElement('ks_dn_custom_domain_input_selection', { + selection_input: special_data['select_options'] || [], + })); + break; + case 'date': + case 'datetime': + if (!operator_type) return false; + $value_input = this._ksRenderDateTimeFilterInput(operator_type, field_type); + break; + case 'char': + case 'id': + case 'number' : + if (!operator_type) return false; + else $value_input = $(renderToElement('ks_dn_custom_domain_input_text', {})); + break; + default: + return; + } + return $value_input; + }, + + _ksRenderDateTimeFilterInput(operator, field_type){ + var self = this; + var $value_container = $(renderToElement('ks_dn_custom_domain_input_date',{ + operator:operator, + field_type:field_type, + + })); + + if (field_type == 'date'){ + $value_container.find("#datetimepicker1").each((index,item)=>{ + item.value = formatDate(DateTime.now(),{format: "yyyy-MM-dd" }) + }) + + }else{ + $value_container.find("#datetimepicker1").each((index,item)=>{ + item.value = new Date(DateTime.now() + new Date().getTimezoneOffset() * -60 * 1000).toISOString().slice(0, 19) + }) + } + return $value_container; + }, + + ksOnCustomFilterApply(){ + var self = this; + var model_domain = {}; + $('.ks_dn_custom_filter_input_container_section').each((index, filter_container) => { + var field_id = $(filter_container).find('.ks_custom_filter_field_selector').val(); + var field_select = this.ks_dashboard_data.ks_dashboard_custom_domain_filter[field_id]; + var field_type = field_select.type; + var domainValue = []; + var domainArray = []; + var operator = getDomainDisplayedOperators(field_select)[$(filter_container).find('.ks_operator_option_selector').prop('selectedIndex')]; + var ks_label = this.operators.filter((x) => x.symbol === operator) + + var label = field_select.name + ' ' + ks_label[0].description; + if (['date', 'datetime'].includes(field_type)) { + var dateValue = []; + $(filter_container).find(".o_generator_menu_value .o_datepicker").each((index, $input_val) => { + var a = $($input_val).val();; + if (field_type === 'datetime'){ + var b = formatDateTime(DateTime.fromISO(a),{ format: "yyyy-MM-dd HH:mm:ss" }); + var c = formatDateTime(DateTime.fromISO(a),{ format: "dd/MM/yyyy HH:mm:ss" }) ; + }else{ + var b = formatDate(DateTime.fromFormat(a,'yyyy-MM-dd'),{ format: "yyyy-MM-dd" }); + var c = formatDate(DateTime.fromFormat(a,'yyyy-MM-dd'),{ format: "dd/MM/yyyy" }); + } + + domainValue.push(b); + dateValue.push(c); + }); + label = label +' ' + dateValue.join(" and " ); + } else if (field_type === 'selection') { + domainValue = [$(filter_container).find(".o_generator_menu_value").val()] + label = label + ' ' + $(filter_container).find(".o_generator_menu_value").val(); + } + else { + domainValue = [$(filter_container).find(".o_generator_menu_value input").val()] + label = label +' ' + $(filter_container).find(".o_generator_menu_value input").val(); + } + + if (operator === 'between') { + domainArray.push( + [field_select.field_name, '>=', domainValue[0]], + [field_select.field_name, '<=', domainValue[1]] + ); + domainArray.unshift('&'); + } else { + domainArray.push([field_select.field_name, operator, domainValue[0]]); + } + + if(field_select.model in model_domain){ + model_domain[field_select.model]['domain'] = model_domain[field_select.model]['domain'].concat(domainArray); + model_domain[field_select.model]['domain'].unshift('|'); + model_domain[field_select.model]['label'] = model_domain[field_select.model]['label'] + ' or ' + label; + } else { + model_domain[field_select.model] = { + 'domain': domainArray, + 'label': label, + 'model_name': field_select.model_name, + } + } + }); + this._ksAddCustomDomain(model_domain); + }, + + eraseCookie(name) { + document.cookie = name + '=; Max-Age=-99999999; path=/'; + }, + + 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=/"; + }, + + setObjectInCookie(name, object, days) { + var jsonString = JSON.stringify(object); + this.setCookie(name, jsonString, days); + }, + + 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; + }, + + getObjectFromCookie(name) { + var jsonString = this.getCookie(name); + return jsonString ? JSON.parse(jsonString) : null; + }, + + _ksAddCustomDomain(model_domain){ + var self = this; + $(".ks_dn_filter_applied_container").removeClass('ks_hide'); + Object.entries(model_domain).map(([model,val])=>{ + var domain_data = self.ks_dashboard_data.ks_dashboard_domain_data[model]; + var domain_index = { + categ: false, + domain: val['domain'], + label: [val['label']], + model: model, + } + + if (domain_data) { + domain_data.ks_domain_index_data.push(domain_index); + } else { + domain_data = { + 'domain': [], + 'model_name': val.model_name, + 'item_ids': self.ks_dashboard_data.ks_model_item_relation[model], + 'ks_domain_index_data': [domain_index], + } + self.ks_dashboard_data.ks_dashboard_domain_data[model] = domain_data; + } + + $("#ks_dn_custom_filters_container").empty(); + var show_remove_option = false; + self.ks_render_custom_filter(show_remove_option); + + domain_data['domain'] = self._ksMakeDomainFromDomainIndex(domain_data.ks_domain_index_data); + self.state.custom_filter = {...domain_data} + + if(domain_data['domain'][0] !== undefined && domain_data['domain'].length != 0){ + var storedData = this.getObjectFromCookie('FilterOrderData' + self.ks_dashboard_id); + if(storedData !== null ){ + this.eraseCookie('FilterOrderData' + self.ks_dashboard_id); + } + this.setObjectInCookie('FilterOrderData' + self.ks_dashboard_id, self.ks_dashboard_data.ks_dashboard_domain_data, 1); + } + + self.state.pre_defined_filter = {} + self.state.ksDateFilterSelection = 'none' + }) + }, + + ksOnCustomFilterFieldSelect(ev){ + var self =this; + var $parent_container = $(ev.currentTarget.parentElement); + $parent_container.find('.ks_operator_option_selector').remove(); + $parent_container.find('.o_generator_menu_value').remove(); + var field_id = ev.currentTarget.value; + var field_select = self.ks_dashboard_data.ks_dashboard_custom_domain_filter[field_id]; + var field_type = field_select.type; + var ks_operators = getDomainDisplayedOperators(field_select); + var operatorsinfo = ks_operators.map((x)=> getOperatorLabel(x)); + this.operators = ks_operators.map((val,index)=>{ + return{ + 'symbol': val, + 'description': operatorsinfo[index] + } + + }) + var operator_type = self.operators[0]; + var $operator_input = $(renderToElement('ks_dn_custom_domain_input_operator', { + operators: self.operators, + self:self + })); + + $parent_container.append($operator_input); + var $value_input = self._ksRenderCustomFilterInputSection(operator_type, ks_field_type[field_type], field_select.special_data) + if ($value_input) $parent_container.append($value_input); + }, + ksOnCustomFilterOperatorSelect(ev){ + var $parent_container = $(ev.currentTarget.parentElement); + var operator_symbol = ev.currentTarget.value; + var field_id = $parent_container.find('.ks_custom_filter_field_selector').val(); + var field_select = this.ks_dashboard_data.ks_dashboard_custom_domain_filter[field_id]; + var field_type = field_select.type; + var ks_operators = getDomainDisplayedOperators(field_select); + var operator_type = ks_operators[ev.currentTarget.selectedIndex]; + + $parent_container.find('.o_generator_menu_value').remove(); + var $value_input = this._ksRenderCustomFilterInputSection(operator_type, ks_field_type[field_type], field_select.special_data) + if ($value_input) $parent_container.append($value_input); + }, + + ksOnCustomFilterConditionAdd(){ + var show_remove_option = true; + this.ks_render_custom_filter(show_remove_option); + }, + ksOnCustomFilterConditionRemove(ev){ + ev.stopPropagation(); + $(ev.currentTarget.parentElement).remove(); + }, + + + + +}); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_form_view_dialog.js b/ks_dashboard_ninja/static/src/js/ks_form_view_dialog.js new file mode 100644 index 000000000..c9211f7e5 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_form_view_dialog.js @@ -0,0 +1,30 @@ +/** @odoo-module **/ + +import { FormViewDialog } from "@web/views/view_dialogs/form_view_dialog"; +import { FormController } from "@web/views/form/form_controller"; +import { patch } from "@web/core/utils/patch"; +import { onMounted } from "@odoo/owl"; + +patch(FormViewDialog.prototype, { + setup(){ + onMounted(this._mounted) + super.setup() + }, + _mounted(){ + if (this.props.context && this.props.context.hasOwnProperty('ks_form_view')){ + if (this.props.context.ks_form_view == true){ + $('body').addClass('ks_dn_create_chart') + } + } + }, + + }); +patch(FormController.prototype, { + beforeExecuteActionButton(clickParams){ + if (this.props.context.ks_form_view == true && clickParams.special == 'cancel'){ + $('body').removeClass('ks_dn_create_chart') + } + return super.beforeExecuteActionButton(...arguments) + }, + }); + diff --git a/ks_dashboard_ninja/static/src/js/ks_global_functions.js b/ks_dashboard_ninja/static/src/js/ks_global_functions.js new file mode 100644 index 000000000..924bd4803 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_global_functions.js @@ -0,0 +1,197 @@ +/** @odoo-module **/ + +import { getCurrency } from "@web/core/currency"; +import { formatFloat,formatInteger } from "@web/views/fields/formatters"; + +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; + } + } + + } + +} +return { + globalfunction:globalfunction +} diff --git a/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js b/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js new file mode 100644 index 000000000..1ab33f836 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js @@ -0,0 +1,118 @@ +odoo.define('ks_dashboard_ninja.import_button', function(require) { + + "use strict"; + + var core = require('web.core'); + var _t = core._t; +// var Sidebar = require('web.Sidebar'); + var ListController = require('web.ListController'); + var framework = require('web.framework'); + var Dialog = require('web.Dialog'); + + + ListController.include({ + + + + + _getActionMenuItems: function (state) { + if (!this.hasActionMenus || !this.selectedRecords.length) { + return null; + } + const props = this._super(...arguments); + const otherActionItems = []; + if (this.modelName == "ks_dashboard_ninja.board"){ + if (this.isExportEnable) { + otherActionItems.push({ + description: _t("Export Dashboard"), + callback: this.ks_dashboard_export.bind(this) + }); + } + if (this.archiveEnabled) { + otherActionItems.push({ + description: _t("Archive"), + callback: () => { + Dialog.confirm(this, _t("Are you sure that you want to archive all the selected records?"), { + confirm_callback: () => this._toggleArchiveState(true), + }); + } + }, { + description: _t("Unarchive"), + callback: () => this._toggleArchiveState(false) + }); + } + if (this.activeActions.delete) { + otherActionItems.push({ + description: _t("Delete"), + callback: () => this._onDeleteSelectedRecords() + }); + }}else{ + if (this.isExportEnable) { + otherActionItems.push({ + description: _t("Export"), + callback: () => this._onExportData() + }); + } + if (this.archiveEnabled) { + otherActionItems.push({ + description: _t("Archive"), + callback: () => { + Dialog.confirm(this, _t("Are you sure that you want to archive all the selected records?"), { + confirm_callback: () => this._toggleArchiveState(true), + }); + } + }, { + description: _t("Unarchive"), + callback: () => this._toggleArchiveState(false) + }); + } + if (this.activeActions.delete) { + otherActionItems.push({ + description: _t("Delete"), + callback: () => this._onDeleteSelectedRecords() + }); + } + + } + return Object.assign(props, { + items: Object.assign({}, this.toolbarActions, { other: otherActionItems }), + context: state.getContext(), + domain: state.getDomain(), + isDomainSelected: this.isDomainSelected, + }); + + }, + + ks_dashboard_export: function() { + this.ks_on_dashboard_export(this.getSelectedIds()); + }, + + ks_on_dashboard_export: function(ids) { + var self = this; + this._rpc({ + model: 'ks_dashboard_ninja.board', + method: 'ks_dashboard_export', + args: [JSON.stringify(ids)], + }).then(function(result) { + var name = "dashboard_ninja"; + var data = { + "header": name, + "dashboard_data": result, + } + framework.blockUI(); + self.getSession().get_file({ + url: '/ks_dashboard_ninja/export/dashboard_json', + data: { + data: JSON.stringify(data) + }, + complete: framework.unblockUI, + error: (error) => this.call('crash_manager', 'rpc_error', error), + }); + }) + }, + + + }); + core.action_registry.add('ks_dashboard_ninja.import_button', ListController); + return ListController; +}); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_quick_edit_view.js b/ks_dashboard_ninja/static/src/js/ks_quick_edit_view.js new file mode 100644 index 000000000..e28bcbb08 --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_quick_edit_view.js @@ -0,0 +1,166 @@ +/** @odoo-module **/ + + +import Widget from "@web/legacy/js/core/widget"; +import { _t } from "@web/core/l10n/translation"; +//var data = require('web.data'); +import { FormViewDialog } from "@web/views/view_dialogs/form_view_dialog"; +//var AbstractAction = require('web.AbstractAction'); +import { session } from "@web/session"; + +var QuickEditView = Widget.extend({ + + template: 'ksQuickEditViewOption', + + events: { + 'click .ks_quick_edit_action': 'ksOnQuickEditViewAction', + }, + + init: function(parent, options) { + this._super.apply(this, arguments); + this.ksDashboardController = parent; + + this.ksOriginalItemData = $.extend({}, options.item); + this.item = options.item; + this.item_name = options.item ? options.item.name:false; + + }, + + + willStart: function() { + var self = this; + return $.when(this._super()).then(function() { + return self._ksCreateController(); + }); + }, + + _ksCreateController: function() { + var self = this; + + self.context = $.extend({}, session.user_context); + self.context['form_view_ref'] = 'ks_dashboard_ninja.item_quick_edit_form_view'; + self.context['res_id'] = this.item.id; + self.res_model = "ks_dashboard_ninja.item"; + self.dataset = new data.DataSet(this, this.res_model, self.context); + var def = self.loadViews(this.dataset.model, self.context, [ + [false, 'list'], + [false, 'form'] + ], {}); + return $.when(def).then(function(fieldsViews) { + self.formView = new FormViewDialog(fieldsViews.form, { + context: self.context, + modelName: self.res_model, + userContext: self.getSession().user_context, + currentId: self.item.id, + index: 0, + mode: 'edit', + footerToButtons: true, + default_buttons: false, + withControlPanel: false, + ids: [self.item.id], + }); + var def2 = self.formView.getController(self); + return $.when(def2).then(function(controller) { + self.controller = controller; + self.controller._confirmChange = self._confirmChange.bind(self); + }); + }); + }, + + //This Function is replacing Controllers to intercept in between to fetch changed data and update our item view. + _confirmChange: function(id, fields, e) { + if (e.name === 'discard_changes' && e.target.reset) { + // the target of the discard event is a field widget. In that + // case, we simply want to reset the specific field widget, + // not the full view + return e.target.reset(this.controller.model.get(e.target.dataPointID), e, true); + } + + var state = this.controller.model.get(this.controller.handle); + this.controller.renderer.confirmChange(state, id, fields, e); + return this.ks_Update_item(); + }, + + ks_Update_item: function() { + var self = this; + var ksChanges = this.controller.renderer.state.data; + + if (ksChanges['name']) this.item['name'] = ksChanges['name']; + + self.item['ks_font_color'] = ksChanges['ks_font_color']; + self.item['ks_icon_select'] = ksChanges['ks_icon_select']; +// self.item['ks_icon'] = ksChanges['ks_icon']; + self.item['ks_background_color'] = ksChanges['ks_background_color']; + self.item['ks_default_icon_color'] = ksChanges['ks_default_icon_color']; + self.item['ks_layout'] = ksChanges['ks_layout']; + self.item['ks_record_count'] = ksChanges['ks_record_count']; + + if (ksChanges['ks_list_view_data']) self.item['ks_list_view_data'] = ksChanges['ks_list_view_data']; + + if (ksChanges['ks_chart_data']) self.item['ks_chart_data'] = ksChanges['ks_chart_data']; + + if (ksChanges['ks_kpi_data']) self.item['ks_kpi_data'] = ksChanges['ks_kpi_data']; + + if (ksChanges['ks_list_view_type']) self.item['ks_list_view_type'] = ksChanges['ks_list_view_type']; + + if (ksChanges['ks_chart_item_color']) self.item['ks_chart_item_color'] = ksChanges['ks_chart_item_color']; + + self.ksUpdateItemView(); + + }, + + start: function() { + var self = this; + this._super.apply(this, arguments); + + }, + + renderElement: function() { + var self = this; + self._super.apply(this, arguments); + self.controller.appendTo(self.$el.find(".ks_item_field_info")); + + self.trigger('canBeRendered', {}); + }, + + ksUpdateItemView: function() { + var self = this; + self.ksDashboardController.ksUpdateDashboardItem([self.item.id]); + self.item_el = $.find('#' + self.item.id + '.ks_dashboarditem_id'); + + }, + + ksDiscardChanges: function() { + var self = this; + self.ksDashboardController.ksFetchUpdateItem(self.item.id); + self.destroy(); + }, + + + ksOnQuickEditViewAction: function(e) { + var self = this; + self.need_reset = false; + var options = { + 'need_item_reload': false + } + if (e.currentTarget.dataset['ksItemAction'] === 'saveItemInfo') { + this.controller.saveRecord().then(function() { + self.ksDiscardChanges(); + }) + } else if (e.currentTarget.dataset['ksItemAction'] === 'fullItemInfo') { + this.trigger('openFullItemForm', {}); + } else { + self.ksDiscardChanges(); + } + }, + + destroy: function(options) { + this.trigger('canBeDestroyed', {}); + this.controller.destroy(); + this._super(); + }, +}); + +return { + QuickEditView: QuickEditView, +}; \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js b/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js new file mode 100644 index 000000000..c612ecf7f --- /dev/null +++ b/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js @@ -0,0 +1,1526 @@ +odoo.define('ks_dashboard_ninja.ks_to_do_dashboard_filter', function (require) { +"use strict"; + +var KsDashboard = require('ks_dashboard_ninja.ks_dashboard'); +var core = require('web.core'); +var _t = core._t; +var QWeb = core.qweb; +var Dialog = require('web.Dialog'); +var config = require('web.config'); + +return KsDashboard.include({ + events: _.extend({}, KsDashboard.prototype.events, { + 'click .ks_edit_content': '_onKsEditTask', + 'click .ks_delete_content': '_onKsDeleteContent', + 'click .header_add_btn': '_onKsAddTask', + 'click .ks_create_task': '_onKsCreateTask', +// 'click .ks_add_section': '_onKsAddSection', + 'click .ks_li_tab': '_onKsUpdateAddButtonAttribute', + 'click .ks_do_item_active_handler': '_onKsActiveHandler', + 'click .ks_li_tab': 'ksOnToDoClick', +// 'click .ks_edit_map_form': 'ksOpenForm' + }), + + ksOnToDoClick: function(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); + }, + + ksRenderDashboardItems: function(items) { + var self = this; + self.$el.find('.print-dashboard-btn').addClass("ks_pro_print_hide"); + if (self.ks_dashboard_data.ks_gridstack_config) { + self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_gridstack_config); + } + var item_view; + var ks_container_class = 'grid-stack-item', + ks_inner_container_class = 'grid-stack-item-content'; + for (var i = 0; i < items.length; i++) { + if (self.grid) { + + if (items[i].ks_dashboard_item_type === 'ks_tile') { + var item_view = self._ksRenderDashboardTile(items[i]) + if (items[i].id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($(item_view)[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h,autoPosition:true,minW:2,maxW:null,minH:2,maxH:2,id:items[i].id,}); + } + else{ + self.grid.addWidget($(item_view)[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h,autoPosition:false,minW:2,maxW:null,minH:2,maxH:2,id:items[i].id,}); + } + } else { + self.grid.addWidget($(item_view)[0], {x:0, y:0, w:3, h:2,autoPosition:true,minW:2,maxW:null,minH:2,maxH:2,id:items[i].id}); + } + } else if (items[i].ks_dashboard_item_type === 'ks_list_view') { + self._renderListView(items[i], self.grid) + } else if (items[i].ks_dashboard_item_type === 'ks_kpi') { + var $kpi_preview = self.renderKpi(items[i], self.grid) + if (items[i].id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($kpi_preview[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h,autoPosition:true,minW:2,maxW:null,minH:2,maxH:3,id:items[i].id}); + } + else{ + self.grid.addWidget($kpi_preview[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h,autoPosition:false,minW:2,maxW:null,minH:2,maxH:3,id:items[i].id}); + } + } else { + self.grid.addWidget($kpi_preview[0], {x:0, y:0, w:3, h:2,autoPosition:true,minW:2,maxW:null,minH:2,maxH:3,id:items[i].id}); + } + + } else if (items[i].ks_dashboard_item_type === 'ks_to_do'){ + var $to_do_preview = self.ksRenderToDoDashboardView(items[i])[0]; + if (items[i].id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($to_do_preview[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h, autoPosition:true, minW:5, maxW:null, minH:2, maxH:null, id:items[i].id}); + } + else{ + self.grid.addWidget($to_do_preview[0], {x:self.gridstackConfig[items[i].id].x, y:self.gridstackConfig[items[i].id].y, w:self.gridstackConfig[items[i].id].w, h:self.gridstackConfig[items[i].id].h, autoPosition:false, minW:5, maxW:null, minH:2, maxH:null, id:items[i].id}); + } + } else { + self.grid.addWidget($to_do_preview[0], {x:0, y:0, w:6, h:4, autoPosition:true, minW:5, maxW:null, minH:2, maxH:null, id:items[i].id}) + } + } else if(items[i].ks_dashboard_item_type === 'ks_flower_view'){ + self._ksflowerchart(items[i], self.grid) + } else if(items[i].ks_dashboard_item_type === 'ks_radialBar_chart'){ + self._renderradialchart(items[i], self.grid) + } else if (items[i].ks_dashboard_item_type === 'ks_map_view') { + self._renderMap(items[i], self.grid) + }else if(items[i].ks_dashboard_item_type === 'ks_funnel_chart' || items[i].ks_dashboard_item_type === 'ks_bullet_chart'){ + self._ksfunnelchart(items[i],self.grid) + }else{ + self._renderGraph(items[i], self.grid) + } + } + } + }, + + ksRenderToDoDashboardView: function(item){ + var self = this; + var item_title = item.name; + var item_id = item.id; + if (item.ks_info){ + var ks_description = item.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + var list_to_do_data = JSON.parse(item.ks_to_do_data) + var ks_header_color = self._ks_get_rgba_format(item.ks_header_bg_color); + var 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); + var $ksItemContainer = self.ksRenderToDoView(item); + var $ks_gridstack_container = $(QWeb.render('ks_to_do_dashboard_container', { + ks_chart_title: item_title, + ksIsDashboardManager: self.ks_dashboard_data.ks_dashboard_manager, + ksIsUser: true, + ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list, + item_id: item_id, + to_do_view_data: list_to_do_data, + ks_rgba_button_color:ks_rgba_button_color, + ks_info: ks_description, + ks_company:item.ks_company + })).addClass('ks_dashboarditem_id') + $ks_gridstack_container.find('.ks_card_header').addClass('ks_bg_to_color').css({"background-color": ks_header_color }); + $ks_gridstack_container.find('.ks_card_header').addClass('ks_bg_to_color').css({"color": ks_font_color + ' !important' }); + $ks_gridstack_container.find('.ks_li_tab').addClass('ks_bg_to_color').css({"color": ks_font_color + ' !important' }); + $ks_gridstack_container.find('.ks_list_view_heading').addClass('ks_bg_to_color').css({"color": ks_font_color + ' !important' }); + $ks_gridstack_container.find('.ks_to_do_card_body').append($ksItemContainer) + return [$ks_gridstack_container, $ksItemContainer]; + }, + + ksRenderToDoView: function(item, ks_tv_play=false) { + var self = this; + var item_id = item.id; + var list_to_do_data = JSON.parse(item.ks_to_do_data); + var $todoViewContainer = $(QWeb.render('ks_to_do_dashboard_inner_container', { + ks_to_do_view_name: "Test", + to_do_view_data: list_to_do_data, + item_id: item_id, + ks_tv_play: ks_tv_play + })); + + return $todoViewContainer + }, + +// _onKsCreateTask + + _onKsEditTask: function(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 $content = "
" + var dialog = new Dialog(this, { + title: _t('Edit Task'), + size: 'medium', + $content: $content, + buttons: [ + { + text: 'Save', + classes: 'btn-primary', + click: function(e){ + var content = $(e.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)); + }, + close: true, + }, + { + text: _t('Close'), + classes: 'btn-secondary o_form_button_cancel', + close: true, + } + ], + }); + dialog.open(); + }, + + onSaveTask: function(content, ks_description_id, ks_item_id, ks_section_id){ + var self = this; + this._rpc({ + model: 'ks_to.do.description', + method: 'write', + args: [ks_description_id, { + "ks_description": content + }], + }).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: function(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; + + Dialog.confirm(this, (_t("Are you sure you want to remove this task?")), { + confirm_callback: function() { + + self._rpc({ + model: 'ks_to.do.description', + method: 'unlink', + args: [parseInt(ks_description_id)], + }).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); + }); + }); + }, + }); + }, + + _onKsAddTask: function(e){ + var self = this; + var ks_section_id = e.currentTarget.dataset.sectionId; + var ks_item_id = e.currentTarget.dataset.itemId; + var $content = "
" + var dialog = new Dialog(this, { + title: _t('New Task'), + $content: $content, + size: 'medium', + buttons: [ + { + text: 'Save', + classes: 'btn-primary ks_create_task', + click: function(e){ + var content = $(e.currentTarget.parentElement.parentElement).find('.ks_section').val(); + if (content.length === 0){ + +// this.do_notify(false, _t('Successfully sent to printer!')); + } + else{ + self._onCreateTask(content, parseInt(ks_section_id), parseInt(ks_item_id)); + } + }, + close: true, + }, + { + text: _t('Close'), + classes: 'btn-secondary o_form_button_cancel', + close: true, + } + ], + }); + dialog.open(); + }, + + _onCreateTask: function(content, ks_section_id, ks_item_id){ + var self = this; + this._rpc({ + model: 'ks_to.do.description', + method: 'create', + args: [{ + ks_to_do_header_id: ks_section_id, + ks_description: content, + }], + }).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); + }); + + }); + }, + + _onKsUpdateAddButtonAttribute: function(e){ + var item_id = e.currentTarget.dataset.itemId; + var sectionId = e.currentTarget.dataset.sectionId; + $(".header_add_btn[data-item-id=" + item_id + "]").attr('data-section-id', sectionId); + }, + + _onKsActiveHandler: function(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); + this._rpc({ + model: 'ks_to.do.description', + method: 'write', + args: [parseInt(content_id), { + "ks_active": ks_value + }], + }).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); + }); + }); + }, + + ks_radial_container_option: function(chart_title, ksIsDashboardManager, ksIsUser, ks_dashboard_list, chart_id, ks_info, ksChartColorOptions, ks_company, ks_dashboard_item_type){ + var container_data = { + ks_chart_title: chart_title, + ksIsDashboardManager: ksIsDashboardManager, + ksIsUser:ksIsUser, + ks_dashboard_list: ks_dashboard_list, + chart_id: chart_id, + ks_info:ks_info, + ksChartColorOptions: ksChartColorOptions, + ks_company:ks_company, + ks_dashboard_item_type:ks_dashboard_item_type, + } + return container_data; + }, + + _renderradialchart: function (item) { + var self = this; + var isDrill = item.isDrill ? item.isDrill : false; + this.chart + this.ksColorOptions = ["default","dark","moonrise","material"] + var chart_id = item.id; + var radial_title = item.name; + if (item.ks_info){ + var ks_description = item.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + var container_data = self.ks_radial_container_option(radial_title, self.ks_dashboard_data.ks_dashboard_manager, true, self.ks_dashboard_data.ks_dashboard_list, chart_id, ks_description, this.ksColorOptions, item.ks_company,item.ks_dashboard_item_type); + + var $ks_gridstack_container = $(QWeb.render('ks_gridstack_container', container_data)).addClass('ks_dashboarditem_id'); + $ks_gridstack_container.find(".ks_dashboard_item_button_container").addClass("ks_radial_item_container"); + var ksLayoutGridId = $(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id') + if(ksLayoutGridId && ksLayoutGridId != 'ks_default'){ + self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_child_boards[parseInt(ksLayoutGridId)][1]) + } + + parseInt($(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id')) + if (chart_id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:true,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } + else{ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:false,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } + } else { + self.grid.addWidget($ks_gridstack_container[0], {x:0, y:0, w:5, h:4,autoPosition:true,minW:4,maxW:null,minH:3,maxH:null, id :chart_id}); + } + self.ksrenderradialchart($ks_gridstack_container,item); + }, + ksrenderradialchart($ks_gridstack_container,item){ + var self =this; + if($ks_gridstack_container.find('.ks_chart_card_body').length){ + var radialRender = $ks_gridstack_container.find('.ks_chart_card_body'); + }else{ + $($ks_gridstack_container.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var radialRender = $ks_gridstack_container.find('.ks_chart_card_body'); + } + var radial_data = JSON.parse(item.ks_chart_data); + var ks_labels = radial_data['labels']; + var ks_data=[]; + let data = []; + if (radial_data.datasets){ + for (let i=0 ; i").text("No Data Available.")) + } + return $ks_gridstack_container; + }, + + _ksflowerchart:function(item){ + var self = this; + var isDrill = item.isDrill ? item.isDrill : false; + this.chart + this.ksColorOptions = ["default","dark","moonrise","material"] + var chart_id = item.id; + var flower_title = item.name; + if (item.ks_info){ + var ks_description = item.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + var container_data = this.ks_flower_container_option(flower_title, self.ks_dashboard_data.ks_dashboard_manager, true, self.ks_dashboard_data.ks_dashboard_list, chart_id, ks_description, this.ksColorOptions, item.ks_company,item.ks_dashboard_item_type); + + var $ks_gridstack_container = $(QWeb.render('ks_gridstack_container', container_data)).addClass('ks_dashboarditem_id'); + $ks_gridstack_container.find(".ks_dashboard_item_button_container").addClass("ks_flower_item_container"); + var ksLayoutGridId = $(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id') + if(ksLayoutGridId && ksLayoutGridId != 'ks_default'){ + self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_child_boards[parseInt(ksLayoutGridId)][1]) + } + parseInt($(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id')) + if (chart_id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:true,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } + else{ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:false,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } + } else { + self.grid.addWidget($ks_gridstack_container[0], {x:0, y:0, w:5, h:4,autoPosition:true,minW:4,maxW:null,minH:3,maxH:null, id :chart_id}); + } + self.ksrenderflowerchart($ks_gridstack_container,item); + }, + ksrenderflowerchart($ks_gridstack_container,item){ + var self =this; + if($ks_gridstack_container.find('.ks_chart_card_body').length){ + var flowerRender = $ks_gridstack_container.find('.ks_chart_card_body'); + }else{ + $($ks_gridstack_container.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var flowerRender = $ks_gridstack_container.find('.ks_chart_card_body'); + } + var flower_data = JSON.parse(item.ks_chart_data); + var ks_labels = flower_data['labels']; + var ks_data=[]; + let data = []; + if (flower_data.datasets){ + for (let i=0 ; i").text("No Data Available.")) + } + return $ks_gridstack_container; + }, + + ks_flower_container_option: function(chart_title, ksIsDashboardManager, ksIsUser, ks_dashboard_list, chart_id, ks_info, ksChartColorOptions, ks_company,ks_dashboard_item_type){ + var container_data = { + ks_chart_title: chart_title, + ksIsDashboardManager: ksIsDashboardManager, + ksIsUser:ksIsUser, + ks_dashboard_list: ks_dashboard_list, + chart_id: chart_id, + ks_info:ks_info, + ksChartColorOptions: ksChartColorOptions, + ks_company:ks_company, + ks_dashboard_item_type:ks_dashboard_item_type + } + return container_data; + }, + + _renderMap: function (item) { + var self = this; + var isDrill = item.isDrill ? item.isDrill : false; + this.chart + var map_title = item.name; + var map_id = item.id; + if (item.ks_info){ + var ks_description = item.ks_info.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + var container_data = this.ks_map_container_option(map_title, self.ks_dashboard_data.ks_dashboard_manager, true, self.ks_dashboard_data.ks_dashboard_list, map_id, ks_description, item.ks_company, item.ks_dashboard_item_type) + var $ks_map_view_tmpl = $(QWeb.render('ks_map_view_tmpl', container_data)).addClass('ks_dashboarditem_id'); + $ks_map_view_tmpl.find(".ks_dashboard_item_button_container").addClass("ks_map_item_container"); + var ksLayoutGridId = $(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id') + if(ksLayoutGridId && ksLayoutGridId != 'ks_default'){ + self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_child_boards[parseInt(ksLayoutGridId)][1]) + } + parseInt($(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id')) + if (map_id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($ks_map_view_tmpl[0], {x:self.gridstackConfig[map_id].x, y:self.gridstackConfig[map_id].y, w:self.gridstackConfig[map_id].w, h:self.gridstackConfig[map_id].h, autoPosition:true,minW:4,maxW:null,minH:3,maxH:null,id :map_id}); + } + else{ + self.grid.addWidget($ks_map_view_tmpl[0], {x:self.gridstackConfig[map_id].x, y:self.gridstackConfig[map_id].y, w:self.gridstackConfig[map_id].w, h:self.gridstackConfig[map_id].h, autoPosition:false,minW:5,maxW:null,minH:3,maxH:null,id :map_id}); + } + } else { + self.grid.addWidget($ks_map_view_tmpl[0], {x:0, y:0, w:5, h:4,autoPosition:true,minW:5,maxW:null,minH:3,maxH:null, id :map_id}); + } + self.ksrendermapview($ks_map_view_tmpl,item); + }, + + async ksrendermapview($ks_map_view_tmpl,item){ + var self =this; + if($ks_map_view_tmpl.find('.ks_map_card_body').length){ + var mapRender = $ks_map_view_tmpl.find('.ks_map_card_body'); + }else{ + $($ks_map_view_tmpl.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var mapRender = $ks_map_view_tmpl.find('.ks_map_card_body'); + } + var map_data = JSON.parse(item.ks_chart_data); + var ks_data=[]; + let data = []; + let label_data = []; + let query_label_data = []; + let domain = []; + let partner_domain = []; + var partners = []; + if (map_data.groupByIds){ + domain = [['id', 'in', map_data.groupByIds]] + const fields = ["partner_latitude", "partner_longitude", "name"]; + await this._rpc({ + model: 'res.partner', + method: 'search_read', + args: [domain, fields], + }).then( (records) => { + partners = records; + }); +// partners = await this.orm.searchRead("res.partner", domain, fields); + } + if ( item.ks_partners_map ) { + partner_domain = [['id', 'in', JSON.parse(item.ks_partners_map)]] + } + var partners_query = []; + const fields = ["partner_latitude", "partner_longitude", "name"]; + await this._rpc({ + model: 'res.partner', + method: 'search_read', + args: [partner_domain, fields], + }).then( (records) => { + partners_query = records; + }); + var ks_labels = map_data['labels']; + if (map_data.datasets.length){ + var ks_data = map_data.datasets[0].data; + } + if (item.ks_data_calculation_type === 'query'){ + for (let i=0 ; i").text("No Data Available.")) + } + return $ks_map_view_tmpl; + }, + + ks_map_container_option: function(map_title, ksIsDashboardManager, ksIsUser, ks_dashboard_list, map_id, ks_info, ks_company, ks_dashboard_item_type){ + var container_data = { + ks_map_title: map_title, + ksIsDashboardManager: ksIsDashboardManager, + ksIsUser:ksIsUser, + ks_dashboard_list: ks_dashboard_list, + map_id: map_id, + ks_info:ks_info, + ks_company:ks_company, + ks_dashboard_item_type:ks_dashboard_item_type + } + return container_data; + }, + +// ksOpenForm: function(e) { +// var self = this; +// var itemId = parseInt(e.currentTarget.dataset.itemId); +// if (itemId){ +// self.do_action({ +// type: 'ir.actions.act_window', +// res_model: 'ks_dashboard_ninja.item', +// res_id: itemId, +// view_id: 'ks_dashboard_ninja_list_form_view', +// views: [ +// [false, 'form'] +// ], +// target: 'current', +// }); +// } +// }, + ks_funnel_container_option: function(chart_title, ksIsDashboardManager, ksIsUser, ks_dashboard_list, chart_id, ks_info, ksChartColorOptions, ks_company,ks_dashboard_item_type){ + var container_data = { + ks_chart_title: chart_title, + ksIsDashboardManager: ksIsDashboardManager, + ksIsUser:ksIsUser, + ks_dashboard_list: ks_dashboard_list, + chart_id: chart_id, + ks_info:ks_info, + ksChartColorOptions: ksChartColorOptions, + ks_company:ks_company, + ks_dashboard_item_type:ks_dashboard_item_type + } + return container_data; + }, + _ksfunnelchart:function(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.split('\n'); + var ks_description = ks_description.filter(element => element !== '') + }else { + var ks_description = false; + } + var container_data = this.ks_funnel_container_option(funnel_title, self.ks_dashboard_data.ks_dashboard_manager, true, self.ks_dashboard_data.ks_dashboard_list, chart_id, ks_description, this.ksColorOptions,item.ks_company,item.ks_dashboard_item_type); + + var $ks_gridstack_container = $(QWeb.render('ks_gridstack_container', container_data)).addClass('ks_dashboarditem_id'); + $ks_gridstack_container.find(".ks_dashboard_item_button_container").addClass("ks_funnel_item_container"); + var ksLayoutGridId = $(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id'); + if(ksLayoutGridId && ksLayoutGridId != 'ks_default'){ + self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_child_boards[parseInt(ksLayoutGridId)][1]) + } + parseInt($(self.$el[0]).find('.ks_layout_selected').attr('data-ks_layout_id')) + if (chart_id in self.gridstackConfig) { + if (config.device.isMobile){ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:true,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } + else{ + self.grid.addWidget($ks_gridstack_container[0], {x:self.gridstackConfig[chart_id].x, y:self.gridstackConfig[chart_id].y, w:self.gridstackConfig[chart_id].w, h:self.gridstackConfig[chart_id].h, autoPosition:false,minW:4,maxW:null,minH:3,maxH:null,id :chart_id}); + } + } else { + self.grid.addWidget($ks_gridstack_container[0], {x:0, y:0, w:5, h:4,autoPosition:true,minW:4,maxW:null,minH:3,maxH:null, id :chart_id}); + } + if (item.ks_dashboard_item_type =="ks_funnel_chart"){ + self.ksrenderfunnelchart($ks_gridstack_container,item); + }else if(item.ks_dashboard_item_type =="ks_bullet_chart"){ + self.ksrenderbulletchart($ks_gridstack_container,item) + } + }, + ksrenderfunnelchart($ks_gridstack_container,item){ + var self =this; + if($ks_gridstack_container.find('.ks_chart_card_body').length){ + var funnelRender = $ks_gridstack_container.find('.ks_chart_card_body'); + }else{ + $($ks_gridstack_container.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var funnelRender = $ks_gridstack_container.find('.ks_chart_card_body'); + } + var funnel_data = JSON.parse(item.ks_chart_data); + if (funnel_data['labels'] && funnel_data['datasets']){ + var ks_labels = funnel_data['labels']; + var ks_data = funnel_data.datasets[0].data; + const ks_sortobj = Object.fromEntries( + ks_labels.map((key, index) => [key, ks_data[index]]), + ); + const keyValueArray = Object.entries(ks_sortobj); + keyValueArray.sort((a, b) => b[1] - a[1]); + + var data=[]; + if (keyValueArray.length){ + for (let i=0 ; i{ + rec.events.on("click",function(ev){ + if (item.ks_data_calculation_type === 'custom'){ + self.onChartCanvasClick_funnel(ev,`${item.id}`, item) + } + }) + }) + }else{ + $ks_gridstack_container.find('.ks_chart_card_body').append($("
").text("No Data Available.")) + } + }else{ + $ks_gridstack_container.find('.ks_chart_card_body').append($("
").text("No Data Available.")) + } + return $ks_gridstack_container; + }, + + ksrenderbulletchart($ks_gridstack_container,item){ + var self =this; + if($ks_gridstack_container.find('.ks_chart_card_body').length){ + var funnelRender = $ks_gridstack_container.find('.ks_chart_card_body'); + }else{ + $($ks_gridstack_container.find('.ks_dashboarditem_chart_container')[0]).append("
"); + var funnelRender = $ks_gridstack_container.find('.ks_chart_card_body'); + } + var funnel_data = JSON.parse(item.ks_chart_data); + var ks_labels = funnel_data['labels']; + var ks_data = funnel_data.datasets; + var data=[]; + if (ks_data.length && ks_labels.length){ + for (let i=0 ; i").text("No Data Available.")) + } + return $ks_gridstack_container; + }, + + async onChartCanvasClick_funnel(evt,item_id,item){ + var self = this; + if (item_id in self.ksUpdateDashboard) { + clearInterval(self.ksUpdateDashboard[item_id]); + delete self.ksUpdateDashboard[item_id] + } + 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; + 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; + } + } + else{ + var activePoint = evt.target.dataItem.dataContext; + } + if (activePoint) { + if (activePoint.category){ + for (let i=0 ; i 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); diff --git a/ks_dashboard_ninja/static/src/widgets/color_picker/ks_color_picker.xml b/ks_dashboard_ninja/static/src/widgets/color_picker/ks_color_picker.xml new file mode 100644 index 000000000..da15df002 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/color_picker/ks_color_picker.xml @@ -0,0 +1,11 @@ + + + + + Transparency : + + + + \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.js b/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.js new file mode 100644 index 000000000..c27fc2541 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.js @@ -0,0 +1,67 @@ +/** @odoo-module **/ +import {registry} from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +const {Component,useRef,useState,onWillStart} = owl; + +export class KsKeywordSelection extends Component { + static template = 'KsKeywordSelection'; + setup() { + super.setup(); + this.props.record.data.ks_import_id; + this.input = useRef('ks_input'); + this.search = useRef('ks_search'); + this.ks_sample_final_data = []; + this.state = useState({ values: []}); + this._rpc = useService("rpc"); + onWillStart(async()=>{ + this.ks_data_model = await this._rpc('/web/dataset/call_kw/ks_dashboard_ninja.arti_int/ks_get_keywords',{ + model:'ks_dashboard_ninja.arti_int', + method:'ks_get_keywords', + args:[], + kwargs: {}, + }) + this.state.values = this.ks_data_model + + }); + } + + _onKeyup(ev) { + var value = ev.target.value; + var self=this; + var ks_active_target = $(self.search.el).find(".active") + if (value.length){ + var ks_value = value.toUpperCase(); + self.state.values =[]; + if (this.ks_data_model){ + this.ks_data_model.forEach((item) =>{ + if (item.value.toUpperCase().indexOf(ks_value) >-1){ + self.state.values.push(item) + } + }) + self.state.values.splice(0,0,{"value":value,'id':0}) + + $(self.search.el).removeClass('d-none'); + $(self.search.el).addClass('d-block') + } + }else{ + this.state.values = this.ks_data_model + $(self.search.el).removeClass('d-none'); + $(self.search.el).addClass('d-block') + this.props.record.update({[this.props.name]: ""}) + } + } + + _onResponseSelect(ev) { + var self = this; + var value = $(ev.currentTarget).find(".ai-title")[0].textContent; + this.props.record.update({[this.props.name]: value }); +// self.props.update(value); + self.input.el.value = value; + $(ev.currentTarget).addClass("active"); + } +} +export const KsKeywordSelectionfield = { + component: KsKeywordSelection, +} + +registry.category("fields").add('ks_keyword_selection', KsKeywordSelectionfield); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.xml b/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.xml new file mode 100644 index 000000000..37d135b15 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_ai_keyword/ks_ai_keyword.xml @@ -0,0 +1,40 @@ + + + +
+
+ +
+
+ + +
+
+ +
+
+ Generate With AI +
+
+ +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_bullet_chart/ks_bullet_chart.js b/ks_dashboard_ninja/static/src/widgets/ks_bullet_chart/ks_bullet_chart.js new file mode 100644 index 000000000..0d7e02352 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_bullet_chart/ks_bullet_chart.js @@ -0,0 +1,226 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { CharField } from "@web/views/fields/char/char_field"; +const { Component,reactive, onWillUnmount, onWillUpdateProps, useEffect, useRef, useState, onMounted, willStart } = owl; + +export class ks_bullet_chart extends Component{ + setup(){ + var self =this; + this.root =null; + this.bulletRef = useRef("bullet"); + useEffect(() => { + if (this.root){ + this.root.dispose() + } + this._Ks_render() + }); + +} + + _Ks_render(){ + var self = this; + var rec = this.props.record.data; + var rec = this.props.record.data; + if ($(self.bulletRef.el).find("div.graph_text").length){ + $(self.bulletRef.el).find("div.graph_text").remove(); + } + if (rec.ks_dashboard_item_type === 'ks_bullet_chart'){ + if(rec.ks_data_calculation_type !== "query"){ + if (rec.ks_model_id) { + if (rec.ks_chart_groupby_type == 'date_type' && !rec.ks_chart_date_groupby) { + return $(self.bulletRef.el).append($("
").text("Select Group by date to create chart based on date groupby")); + } else if (rec.ks_chart_data_count_type === "count" && !rec.ks_chart_relation_groupby) { + $(self.bulletRef.el).append($("
").text("Select Group By to create chart view")); + } else if (rec.ks_chart_data_count_type !== "count" && (rec.ks_chart_measure_field.count === 0 || !rec.ks_chart_relation_groupby)) { + $(self.bulletRef.el).append($("
").text("Select Measure and Group By to create chart view")); + } else if (!rec.ks_chart_data_count_type) { + $(self.bulletRef.el).append($("
").text("Select Chart Data Count Type")); + } else { + this.get_bullet_chart(rec); + } + } else { + $(self.bulletRef.el).append($("
").text("Select a Model first.")); + } + }else if(rec.ks_data_calculation_type === "query" && rec.ks_query_result) { + if(rec.ks_xlabels && rec.ks_ylabels){ + this.get_bullet_chart(rec); + } else { + $(self.bulletRef.el).append($("
").text("Please choose the X-labels and Y-labels")); + } + }else { + $(self.bulletRef.el).append($("
").text("Please run the appropriate Query")); + } + + } + } + get_bullet_chart(rec){ + var self = this; + + if($(this.bulletRef.el).find(".graph_text").length){ + $(this.bulletRef.el).find(".graph_text").remove(); + } + const chart_data = JSON.parse(this.props.record.data.ks_chart_data); + var ks_labels = chart_data['labels']; + var ks_data = chart_data.datasets; + + let data=[]; + if (ks_data.length){ + for (let i=0 ; i").text("No Data Available.")); + } + + } +} +ks_bullet_chart.template = "Ksbulletchart"; +export const ks_bullet_chart_field = { + component:ks_bullet_chart, + supportedTypes : ["char"] +}; +registry.category("fields").add("ks_bullet_chart", ks_bullet_chart_field); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_bullet_chart/ks_bullet_chart.xml b/ks_dashboard_ninja/static/src/widgets/ks_bullet_chart/ks_bullet_chart.xml new file mode 100644 index 000000000..6a9a9d7ab --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_bullet_chart/ks_bullet_chart.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_funnel_chart/ks_funnel_chart.js b/ks_dashboard_ninja/static/src/widgets/ks_funnel_chart/ks_funnel_chart.js new file mode 100644 index 000000000..72618e7ed --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_funnel_chart/ks_funnel_chart.js @@ -0,0 +1,152 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { CharField } from "@web/views/fields/char/char_field"; +const { Component, useEffect, useRef, useState } = owl; + +export class ks_funnel_chart extends Component{ + setup(){ + var self =this; + this.root =null; + this.funnelRef = useRef("funnel"); + useEffect(() =>{ + if(this.root){ + this.root.dispose() + } + this._Ks_render() + }); + } + + _Ks_render(){ + var self = this; + var rec = this.props.record.data; + var rec = this.props.record.data; + if ($(self.funnelRef.el).find("div.graph_text").length){ + $(self.funnelRef.el).find("div.graph_text").remove(); + } + if (rec.ks_dashboard_item_type === 'ks_funnel_chart'){ + if(rec.ks_data_calculation_type !== "query"){ + if (rec.ks_model_id) { + if (rec.ks_chart_groupby_type == 'date_type' && !rec.ks_chart_date_groupby) { + return $(self.funnelRef.el).append($("
").text("Select Group by date to create chart based on date groupby")); + } else if (rec.ks_chart_data_count_type === "count" && !rec.ks_chart_relation_groupby) { + $(self.funnelRef.el).append($("
").text("Select Group By to create chart view")); + } else if (rec.ks_chart_data_count_type !== "count" && (rec.ks_chart_measure_field.count === 0 || !rec.ks_chart_relation_groupby)) { + $(self.funnelRef.el).append($("
").text("Select Measure and Group By to create chart view")); + } else if (!rec.ks_chart_data_count_type) { + $(self.funnelRef.el).append($("
").text("Select Chart Data Count Type")); + } else { + this.get_funnel_chart(rec); + } + } else { + $(self.funnelRef.el).append($("
").text("Select a Model first.")); + } + }else if(rec.ks_data_calculation_type === "query" && rec.ks_query_result) { + if(rec.ks_xlabels && rec.ks_ylabels){ + this.get_funnel_chart(rec); + } else { + $(self.funnelRef.el).append($("
").text("Please choose the X-labels and Y-labels")); + } + }else { + $(self.funnelRef.el).append($("
").text("Please run the appropriate Query")); + + } + + } + } + + get_funnel_chart(rec){ + + if($(this.funnelRef.el).find(".graph_text").length){ + $(this.funnelRef.el).find(".graph_text").remove(); + } + if(this.props.record.data.ks_chart_data){ + const chart_data = JSON.parse(this.props.record.data.ks_chart_data); + var ks_labels = chart_data['labels']; + var ks_data = chart_data.datasets[0].data; + const ks_sortobj = Object.fromEntries( + ks_labels.map((key, index) => [key, ks_data[index]]), + ); + const keyValueArray = Object.entries(ks_sortobj); + keyValueArray.sort((a, b) => b[1] - a[1]); + + var data=[]; + if (keyValueArray.length){ + for (let i=0 ; i").text("No Data Available.")); + } + }else{ + $(this.funnelRef.el).append($("
").text("No Data Available.")); + } + } +} + +ks_funnel_chart.template = "Ksfunnelchart"; +export const ks_funnel_chart_field = { + component: ks_funnel_chart, + supportedTypes : ["char"] +} +registry.category("fields").add("ks_funnel_chart", ks_funnel_chart_field); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_funnel_chart/ks_funnel_chart.xml b/ks_dashboard_ninja/static/src/widgets/ks_funnel_chart/ks_funnel_chart.xml new file mode 100644 index 000000000..ebea185b3 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_funnel_chart/ks_funnel_chart.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_graph_view/ks_graph_view.js b/ks_dashboard_ninja/static/src/widgets/ks_graph_view/ks_graph_view.js new file mode 100644 index 000000000..dedc55aa3 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_graph_view/ks_graph_view.js @@ -0,0 +1,884 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { CharField } from "@web/views/fields/char/char_field"; +const { Component,reactive, onWillUnmount, onWillUpdateProps, useEffect, useRef, useState, onMounted, willStart } = owl; + +export class KsGraphPreview extends Component{ + setup(){ + var self =this; + this.root =null; + this.graphref = useRef("graph"); + this.kschartref = useRef("kschart"); + useEffect(() => { + if (this.root){ + this.root.dispose() + } + this._Ks_render() + }); + +} + _Ks_render(){ + var self = this; + var rec = this.props.record.data; + if ($(self.graphref.el).find("div.graph_text").length){ + $(self.graphref.el).find("div.graph_text").remove(); + } + if (rec.ks_dashboard_item_type !== 'ks_tile' && rec.ks_dashboard_item_type !== 'ks_kpi' && 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_model_id) { + if (rec.ks_chart_groupby_type == 'date_type' && !rec.ks_chart_date_groupby) { + return $(self.graphref.el).append($("
").text("Select Group by date to create chart based on date groupby")); + } else if (rec.ks_dashboard_item_type !== 'ks_scatter_chart' && rec.ks_chart_data_count_type === "count" && !rec.ks_chart_relation_groupby) { + $(self.graphref.el).append($("
").text("Select Group By to create chart view")); + } else if ( rec.ks_dashboard_item_type !== 'ks_scatter_chart' && rec.ks_chart_data_count_type !== "count" && (rec.ks_chart_measure_field.count === 0 || !rec.ks_chart_relation_groupby)) { + $(self.graphref.el).append($("
").text("Select Measure and Group By to create chart view")); + } else if (rec.ks_dashboard_item_type !== 'ks_scatter_chart' && !rec.ks_chart_data_count_type) { + $(self.graphref.el).append($("
").text("Select Chart Data Count Type")); + }else if(rec.ks_dashboard_item_type === "ks_scatter_chart"){ + if(rec.ks_scatter_measure_x_id && rec.ks_chart_measure_field ){ + this.get_chart(rec); + }else{ + $(self.graphref.el).append($("
").text("Please Choose Measures")); + } + } + else { + this.get_chart(rec); + } + } else { + $(self.graphref.el).append($("
").text("Select a Model first.")); + } + }else if(rec.ks_data_calculation_type === "query" && rec.ks_query_result) { + if(rec.ks_xlabels && rec.ks_ylabels){ + this.get_chart(rec); + } else { + $(self.graphref.el).append($("
").text("Please choose the X-labels and Y-labels")); + } + }else { + $(self.graphref.el).append($("
").text("Please run the appropriate Query")); + } + + } + } + get_chart(rec){ + if($(this.graphref.el).find(".graph_text").length){ + $(this.graphref.el).find(".graph_text").remove(); + } + const chart_data = JSON.parse(this.props.record.data.ks_chart_data); + var ks_labels = chart_data['labels']; + var ks_data = chart_data.datasets; + + let data=[]; + if (ks_data && ks_labels){ + if (ks_data.length && ks_labels.length){ + for (let i=0 ; i10? "radial" : "circular", + centerX: am5.percent(80) + }) + } + else{ + item.labels.template.setAll({forceHidden:true}) + } + item.data.setAll(data) + if(self.props.record.data.ks_hide_legend == true && series){ + legend.data.setAll(item.dataItems); + } + + item.appear(1000, 100); + } + break; + case "ks_polarArea_chart": + case "ks_radar_view": + case "ks_flower_view": + case "ks_radialBar_chart": + var chart = this.root.container.children.push(am5radar.RadarChart.new(this.root, { + panX: false, + panY: false, + wheelX: "panX", + wheelY: "zoomX", + radius: am5.percent(80), + layout: this.root.verticalLayout, + })); + if (rec.ks_dashboard_item_type == "ks_flower_view"){ + var xRenderer = am5radar.AxisRendererCircular.new(this.root, {}); + xRenderer.labels.template.setAll({ + radius: 10, + cellStartLocation: 0.2, + cellEndLocation: 0.8 + }); + }else if (rec.ks_dashboard_item_type == "ks_radialBar_chart"){ + var xRenderer = am5radar.AxisRendererCircular.new(this.root, { + strokeOpacity: 0.1, + minGridDistance: 50 + }); + xRenderer.labels.template.setAll({ + radius: 23, + maxPosition: 0.98 + }); + }else{ + var xRenderer = am5radar.AxisRendererCircular.new(this.root, {}); + xRenderer.labels.template.setAll({ + radius: 10 + }); + } + if (rec.ks_dashboard_item_type == "ks_radialBar_chart"){ + var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(this.root, { + renderer: xRenderer, + extraMax: 0.1, + tooltip: am5.Tooltip.new(self.root, {}) + })); + + var yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(this.root, { + categoryField: "category", + renderer: am5radar.AxisRendererRadial.new(self.root, { minGridDistance: 20 }) + })); + yAxis.get("renderer").labels.template.setAll({ + oversizedBehavior: "truncate", + textAlign: "center", + maxWidth: 150, + ellipsis: "..." + }); + }else{ + var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(self.root, { + maxDeviation: 0, + categoryField: "category", + renderer: xRenderer, + tooltip: am5.Tooltip.new(self.root, {}) + })); + xAxis.data.setAll(data); + + var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(self.root, { + renderer: am5radar.AxisRendererRadial.new(self.root, {}) + })); + } + + if (rec.ks_dashboard_item_type == "ks_polarArea_chart"){ + for (let k = 0;k").text("No Data Available.")); + } + }else{ + $(this.graphref.el).append($("
").text("No Data Available.")); + } + + } +} +KsGraphPreview.template = "Ksgraphview"; +export const KsGraphPreviewfield = { + component:KsGraphPreview, + supportedTypes : ["char"] +}; +registry.category("fields").add("ks_dashboard_graph_preview", KsGraphPreviewfield); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_graph_view/ks_graph_view.xml b/ks_dashboard_ninja/static/src/widgets/ks_graph_view/ks_graph_view.xml new file mode 100644 index 000000000..801e08c40 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_graph_view/ks_graph_view.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml new file mode 100644 index 000000000..dd2c3ac4b --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_dialog.xml @@ -0,0 +1,37 @@ + + + + +
+
+ + +
+
+ + Note: + + Please use Font Awesome 4.7.0 icons only. E.g. 'fa-bell' or 'bell'. + For more information visit + Font Awesome 4.7.0 +
+
+
+ +
+ +
+
+
+ + + + +
+
+
diff --git a/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_selector_dialog.js b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_selector_dialog.js new file mode 100644 index 000000000..497b4309e --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_icon_selector_dialog.js @@ -0,0 +1,58 @@ +/** @odoo-module */ + +import { Dialog } from "@web/core/dialog/dialog"; +import { Component,useRef } from "@odoo/owl"; + +export class Ksiconselectordialog extends Component { + setup() { + this.ks_modal = useRef("ks_modal") + this.ks_search = useRef("ks_search") + this.ksSelectedIcon = false + } + + ks_icon_container_list(e){ + var self = this; + (this.ks_modal.el.querySelectorAll('.ks_icon_container_list')).forEach((selected_icon) => { + $(selected_icon).removeClass('ks_icon_selected'); + }); + $(e.currentTarget).addClass('ks_icon_selected') + $(".ks_icon_container_open_button").removeClass("d-none") + self.ksSelectedIcon = $(e.currentTarget).find('span').attr('id').split('.')[1] + } + + ks_fa_icon_search(e) { + var self = this + if(this.ks_search.el.querySelectorAll('.ks_fa_search_icon').length > 0){ + this.ks_search.el.querySelectorAll('.ks_fa_search_icon').forEach(function(el){ + el.remove(); + }) + } + var ks_fa_icon_name = this.ks_search.el.querySelectorAll('.ks_modal_icon_input')[0].value; + if (ks_fa_icon_name.slice(0, 3) === "fa-") { + ks_fa_icon_name = ks_fa_icon_name.slice(3) + } + var ks_fa_icon_render = $('
').addClass('ks_icon_container_list ks_fa_search_icon') + $('').attr('id', 'ks.' + ks_fa_icon_name.toLocaleLowerCase()).addClass("fa fa-" + ks_fa_icon_name.toLocaleLowerCase() + " fa-4x").appendTo($(ks_fa_icon_render)) + $(ks_fa_icon_render).appendTo(this.ks_modal.el) + this.ks_modal.el.querySelectorAll('.ks_fa_search_icon').forEach((item) =>{ + item.addEventListener('click', this.ks_icon_container_list.bind(this)) + }) + } + + + async _ks_icon_container_open_button(e){ + try { + await this.props.confirm(this.ksSelectedIcon); + } catch (e) { + this.props.close(); + } + this.props.close(); + } +} +Ksiconselectordialog.template = "Ksicondialog"; +Ksiconselectordialog.props = { + close: Function, + confirm: { type: Function, optional: true }, + ks_icon_set: { type: Object, optional: true }, +} +Ksiconselectordialog.components = { Dialog }; diff --git a/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.js b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.js new file mode 100644 index 000000000..b44a37738 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.js @@ -0,0 +1,40 @@ +/** @odoo-module */ + +import { formatDate, parseDateTime } from "@web/core/l10n/dates"; +import { CharField } from "@web/views/fields/char/char_field"; +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +import { Ksiconselectordialog } from "@ks_dashboard_ninja/widgets/ks_image_widget/ks_icon_selector_dialog" + +const { Component,useEffect, useRef, xml, onWillUpdateProps,onMounted,onWillStart} = owl; + +export class KsImageWidget extends Component { + + setup() { + super.setup(); + this.dialogService = useService("dialog"); + } + + ks_image_widget_icon_container(ev){ + var self = this; + var ks_result = this.dialogService.add(Ksiconselectordialog,{ + ks_icon_set :['home', 'puzzle-piece', 'clock-o', 'comments-o', 'car', 'calendar', 'calendar-times-o', 'bar-chart', 'commenting-o', 'star-half-o', 'address-book-o', 'tachometer', 'search', 'money', 'line-chart', 'area-chart', 'pie-chart', 'check-square-o', 'users', 'shopping-cart', 'truck', 'user-circle-o', 'user-plus', 'sun-o', 'paper-plane', 'rss', 'gears', 'check', 'book'], + confirm: async (info) => { + await this.props.record.update({ [this.props.name]: info}); + + }, + }); + } + + ks_remove_icon(ev){ + var ks_self = this; + this.props.record.update({ [this.props.name]: ""}); + } + +} +KsImageWidget.template="image_widget"; +export const ksImageWidgetField = { + component: KsImageWidget +}; +registry.category("fields").add("ks_image_widget",ksImageWidgetField); + diff --git a/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.xml b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.xml new file mode 100644 index 000000000..eb807cafc --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_image_widget/ks_image_widget.xml @@ -0,0 +1,31 @@ + + + + +
+ +
+ +
+
+ + +
+ Uploading... + + + + +
+
+
+
+
+
+ + +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_item_type_selection/ks_item_type_selection.js b/ks_dashboard_ninja/static/src/widgets/ks_item_type_selection/ks_item_type_selection.js new file mode 100644 index 000000000..c1dc6f7b4 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_item_type_selection/ks_item_type_selection.js @@ -0,0 +1,51 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; +const { Component,useState} = owl; + +export class KsDashboarditemtype extends Component { + setup(){ + var self = this.props; + this.state = useState({ charts: [ + {'id':0,'name':'Tile','Tech_name':'ks_tile'}, + {'id':1,'name':'Bar','Tech_name':'ks_bar_chart'}, + {'id':2,'name':'Horizontal Bar','Tech_name':'ks_horizontalBar_chart'}, + {'id':3,'name':'Line','Tech_name':'ks_line_chart'}, + {'id':4,'name':'Area','Tech_name':'ks_area_chart'}, + {'id':5,'name':'Pie','Tech_name':'ks_pie_chart'}, + {'id':6,'name':'Doughnut','Tech_name':'ks_doughnut_chart'}, + {'id':7,'name':'Polar','Tech_name':'ks_polarArea_chart'}, + {'id':8,'name':'Radial','Tech_name':'ks_radialBar_chart'}, + {'id':9,'name':'Scatter','Tech_name':'ks_scatter_chart'}, + {'id':10,'name':'Radar','Tech_name':'ks_radar_view'}, + {'id':11,'name':'Flower','Tech_name':'ks_flower_view'}, + {'id':12,'name':'Funnel','Tech_name':'ks_funnel_chart'}, + {'id':13,'name':'Bullet','Tech_name':'ks_bullet_chart'}, + {'id':14,'name':'List','Tech_name':'ks_list_view'}, + {'id':15,'name':'Map','Tech_name':'ks_map_view'}, + {'id':16,'name':'To-do','Tech_name':'ks_to_do'}, + {'id':17,'name':'KPI','Tech_name':'ks_kpi'} + ]}); + + } + + onselectitemtype(ev){ + var ks_active_target = $(ev.currentTarget.parentElement).find(".active") + $.each(ks_active_target, function(index,item) { + $(item).removeClass("active") + }); + $(ev.currentTarget).addClass("active") + var ks_value = (ev.currentTarget).innerText + var ks_target = this.state.charts.find((item)=>{ + return item.name === ks_value + }) + this.props.record.update({ [this.props.name]: ks_target['Tech_name']}) + } + + } +KsDashboarditemtype.template="ks_dashboard_item_view_owl"; +export const KsDashboarditemtypeField = { + component: KsDashboarditemtype, + supportedTypes: ["char"], +}; +registry.category("fields").add('ks_dashboard_item_type', KsDashboarditemtypeField); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_item_type_selection/ks_item_type_selection.xml b/ks_dashboard_ninja/static/src/widgets/ks_item_type_selection/ks_item_type_selection.xml new file mode 100644 index 000000000..23c12ef18 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_item_type_selection/ks_item_type_selection.xml @@ -0,0 +1,35 @@ + + + + + +
+ + + +
+
+ image +
+
+ +
+
+
+ +
+
+ image +
+
+ +
+
+
+
+ +
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.js b/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.js new file mode 100644 index 000000000..d21dbc3e4 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.js @@ -0,0 +1,425 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import {globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions'; +import { getCurrency } from "@web/core/currency"; +import { formatFloat,formatInteger } from "@web/views/fields/formatters"; +import { imageCacheKey } from "@web/views/fields/image/image_field"; +import { url } from "@web/core/utils/urls"; + + +const { useEffect, useRef,Component} = owl; + +class KsKpiPreview extends Component { + file_type_magic_word ={'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'} + + ks_get_gcd(a, b) { + return (b == 0) ? a : this.ks_get_gcd(b, a % b); + } + + _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] + ")"; + } + setup() { + super.setup(); + const self = this; + this.ks_kpi_ref = useRef("ks_kpi"); + useEffect(() => this.ks_changes()); + } + + 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, field.ks_precision_digits); + item_info['count_tooltip'] = formatFloat(count, {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; + var ks_color = (target_1 - count) > 0 ? "red" : "green"; + item_info.pre_arrow = (target_1 - count) > 0 ? "down" : "up"; + item_info['ks_comparison'] = true; + var target_deviation = (target_1 - count) > 0 ? Math.round(((target_1 - count) / target_1) * 100) : Math.round((Math.abs((target_1 - count)) / target_1) * 100); + if (target_deviation !== Infinity) item_info.target_deviation = formatInteger(target_deviation)+"%"; + else { + item_info.pre_arrow = false; + item_info.target_deviation = target_deviation; + } + 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) { + 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"; + var 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; + return item_info; + } + get value() { + var self = this; + var field = self.props.record.data; + var kpi_data = JSON.parse(field.ks_kpi_data); + var count_1 = kpi_data[0].record_data; + var count_2 = kpi_data[1] ? kpi_data[1].record_data : undefined; + var target_1 = kpi_data[0].target; + var ks_valid_date_selection = ['l_day', 't_week', 't_month', 't_quarter', 't_year']; + var target_view = field.ks_target_view, + pre_view = field.ks_prev_view; + + 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(field.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%" + } + 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 item_info = { + 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[1], + target_progress_deviation:target_progress_deviation, + icon_select: field.ks_icon_select, + default_icon: field.ks_default_icon, + icon_color: self._get_rgba_format(field.ks_default_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(field.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, + ks_model_id:field.ks_model_id, + ks_model_id_2: field.ks_model_id_2, + ks_record_count_type : field.ks_reocrd_count_type, + ks_dashboard_item_type: field.ks_dashboard_item_type, + ks_record_field : field.ks_record_field, + ks_record_field_2 :field.ks_record_field_2, + ks_rgba_background_color : self._get_rgba_format(field.ks_background_color), + ks_rgba_font_color : self._get_rgba_format(field.ks_font_color), + + } + + 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_icon) { + if (!self.isBinSize(field.ks_icon)) { + // Use magic-word technique for detecting image type + item_info['img_src'] = 'data:image/' + (self.file_type_magic_word[field.ks_icon[0]] || 'png') + ';base64,' + field.ks_icon; + } else { + item_info['img_src'] = url('/web/image', { + model: self.env.model.root.resModel, + id: JSON.stringify(this.props.record.evalContext.id), + field: "ks_icon", + // unique forces a reload of the image when the record has been updated + unique: imageCacheKey(field.write_date), + }); + } + } + 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[0]; + 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); + } + } + + if (kpi_data[1]) { + switch (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[0]; + 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[0]; + 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; + break; + case "Sum": + self.ksSum(count_1, count_2, item_info, field, target_1, kpi_data); + break; + case "Percentage": + self.ksPercentage(count_1, count_2, field, item_info, target_1); + break; + case "Ratio": + var gcd = self.ks_get_gcd(Math.round(count_1), Math.round(count_2)); + if (field.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, {digits: [0, field.ks_precision_digits]}) + ":" + formatFloat(count_2 / gcd, {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; + break; + } + } + return item_info + + + } + + + ks_changes(){ + var self = this; + var field = self.props.record.data; + var ks_valid_date_selection = ['l_day', 't_week', 't_month', 't_quarter', 't_year']; + if (field.ks_kpi_data){ + var kpi_data = JSON.parse(field.ks_kpi_data); + var count_1 = kpi_data[0].record_data + if (kpi_data[1]?.record_data){ + var count_2 = kpi_data[1].record_data + } + if (field.ks_data_comparison === 'Percentage' && field.ks_model_id_2){ + var target_1 = kpi_data[0].target >100 ?100:kpi_data[0].target; + + }else{ + var target_1 = kpi_data[0].target + } + + // target deviation // + if (field.ks_data_comparison === 'Sum' && field.ks_model_id_2 && field.ks_target_view == "Progress Bar"){ + var count = count_1 + count_2 + if (field.ks_multiplier_active){ + count = count * field.ks_multiplier + } + var target_progress_deviation = String(Math.round(((count) / target_1) * 100)) + }else if (field.ks_data_comparison === 'Percentage'&& field.ks_model_id_2 && field.ks_target_view == "Progress Bar"){ + var count = parseInt((count_1 / count_2) * 100) + if (field.ks_multiplier_active){ + count = count * field.ks_multiplier + } + var target_progress_deviation = String(Math.round(count)) + } + else{ + if (field.ks_multiplier_active && field.ks_target_view == "Progress Bar"){ + count_1 = count_1 * field.ks_multiplier + } + var target_progress_deviation = String(Math.round((count_1 / target_1) * 100)); + } + + + // goal enable color // + if (field.ks_goal_enable) { + var diffrence = 0.0 + if (field.ks_data_comparison === 'Sum' && field.ks_model_id_2 && field.ks_target_view == "Number"){ + var count = count_1 + count_2 + if (field.ks_multiplier_active){ + count = count * field.ks_multiplier + } + var diffrence = count - target_1 + }else if (field.ks_data_comparison === 'Percentage' && field.ks_model_id_2 && field.ks_target_view == "Number"){ + var count = parseInt((count_1 / count_2) * 100) + if (field.ks_multiplier_active){ + count = count * field.ks_multiplier + } + var diffrence = count - target_1 + } + else{ + if (field.ks_multiplier_active){ + count_1 = count_1 * field.ks_multiplier + } + var diffrence = count_1 - target_1 + } + + var acheive = diffrence >= 0 ? true : false; + if (acheive) { + $(this.ks_kpi_ref.el).find(".target_deviation").css({ + "color": "green", + }); + } else { + $(this.ks_kpi_ref.el).find(".target_deviation").css({ + "color": "red", + }); + } + } + if ($(this.ks_kpi_ref.el).find('.row').children().length !== 2) { + $(this.ks_kpi_ref.el).find('.row').children().addClass('text-center'); + } + if (field.ks_previous_period && ks_valid_date_selection.indexOf(field.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; + if (pre_acheive) { + $(this.ks_kpi_ref.el).find(".pre_deviation").css({ + "color": "green", + }); + } else { + $(this.ks_kpi_ref.el).find(".pre_deviation").css({ + "color": "red", + }); + } + } + if (field.ks_target_view === "Progress Bar" && field.ks_goal_enable && field.ks_standard_goal_value && field.ks_model_id_2){ + $(this.ks_kpi_ref.el).find('#ks_progressbar').val(parseInt(target_progress_deviation)); + } + if (field.ks_target_view=== "Progress Bar" && field.ks_goal_enable && field.ks_standard_goal_value) { + $(this.ks_kpi_ref.el).find('#ks_progressbar').val(parseInt(target_progress_deviation)); + } + + } + + } + ks_get_gcd(a, b) { + return (b == 0) ? a : this.ks_get_gcd(b, a % b); + } + _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] + ")"; + } + isBinSize(value) { + return /^\d+(\.\d*)? [^0-9]+$/.test(value); + } + + } + +KsKpiPreview.template = "ks_kpi"; +export const KsKpiPreviewfield = { + component :KsKpiPreview, +} +registry.category("fields").add("ks_dashboard_kpi_owlpreview",KsKpiPreviewfield); diff --git a/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml b/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml new file mode 100644 index 000000000..3d3e73e48 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_kpi/ks_kpi.xml @@ -0,0 +1,225 @@ + + + + + + + + + + + + + +
+ Select a record field +
+
+
+ + + + + + + + + + + +
+ Select a reocrd field +
+
+
+
+ + + + + +
+ Please run the appropriate Query +
+
+
+ +
+ Select a model first +
+
+
+ + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
+
+ +
+
+ +
+
+
+ +
+
+ vs Target +
+
+ + + + + + + +
+
+
+ +
+
+ vs Prev +
+
+ + + + +
+
+
+
+
+
+ + +
+
+ + + + + + + + +
+
+
+ +
+
+ + + + / + + + +
+
+
+
+ +
+
+ % +
+
+ +
+
+ vs Prev +
+
+ + + + + +
+
+
+
+
+ + +
+
+ + + + + + + + +
+
+
+ +
+
+ + + / + + + +
+
+ + +
+
+ vs Target +
+
+ + + + + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.js b/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.js new file mode 100644 index 000000000..8fa798382 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.js @@ -0,0 +1,103 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { localization } from "@web/core/l10n/localization"; +import {formatDate,formatDateTime} from "@web/core/l10n/dates"; +import { formatFloat,formatInteger } from "@web/views/fields/formatters"; +import {parseDateTime,parseDate,} from "@web/core/l10n/dates"; + +const { useEffect, useRef, xml, onWillUpdateProps,Component,useState} = owl; + + +class KsListViewPreview extends Component{ + setup() { + super.setup(); + const self = this; + this.state = useState({list_view_data:""}) + this.value() +// useEffect(()=>{ +// this.value() +// }) + + + } + + + value() { + var self = this; + var field = self.props.record.data; + var ks_list_view_name; + if (field.ks_list_view_data){ + var list_view_data = JSON.parse(field.ks_list_view_data); + }else{ + var list_view_data = false + } + var count = field.ks_record_count; + if (field.name) ks_list_view_name = field.name; + else if (field.ks_model_name) ks_list_view_name = field.ks_model_id[1]; + else ks_list_view_name = "Name"; + if (field.ks_list_view_type === "ungrouped" && list_view_data) { + var index_data = list_view_data.date_index; + if (index_data){ + 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'){ + list_view_data.data_rows[j]["data"][index] = formatDate(parseDateTime(date), { format: localization.dateFormat }) + } else{ + let parsedDate = parseDateTime(date,{format: "MM-dd-yyyy HH:mm:ss"}); + list_view_data.data_rows[j]["data"][index] = formatDateTime(parsedDate, { format: localization.dateTimeFormat }) + } + + + }else {list_view_data.data_rows[j]["data"][index] = "";} + } + } + } + } + + if (field.ks_list_view_data) { + var data_rows = list_view_data.data_rows; + if (data_rows){ + 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],{digits: [0, field.ks_precision_digits]}) + } + } else { + list_view_data.data_rows[i].data[j] = ""; + } + } + } + } + } else list_view_data = false; + count = list_view_data && field.ks_list_view_type === "ungrouped" ? count - list_view_data.data_rows.length : false; + count = count ? count <=0 ? false : count : false; + + this.ks_list_view_name = ks_list_view_name, + this.state.list_view_data = list_view_data, + this.count = count, + this.layout = field.ks_list_view_layout, + this.ks_show_records = field.ks_show_records + + + } + +} +KsListViewPreview.template="ks_list_view"; +export const KsListViewPreviewfield={ + component :KsListViewPreview, +} + +registry.category("fields").add("ks_dashboard_list_view_preview", KsListViewPreviewfield); +return { + KsListViewPreview:KsListViewPreview +} + + + + + diff --git a/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml b/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml new file mode 100644 index 000000000..11c786020 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_list_view/ks_list_view.xml @@ -0,0 +1,118 @@ + + + + + + + + + + +
+ Select Fields to show in list view +
+
+
+ + + + + + + +
+ Select Group by Date to show list data. +
+
+
+ +
+ Select Fields and Group By to show in list view +
+
+
+
+ + + + + + +
+ Please run the appropriate Query +
+
+
+ +
+ Select a model first +
+
+
+ + +
+ +
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + +
+
+ + No Data Present + +
+
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_map_view/ks_map_view.js b/ks_dashboard_ninja/static/src/widgets/ks_map_view/ks_map_view.js new file mode 100644 index 000000000..7049606cb --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_map_view/ks_map_view.js @@ -0,0 +1,347 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +const { Component, useEffect, useRef, useState, onMounted } = owl; + + +export class KsMapPreview extends Component { + setup() { + var self =this; + this.root =null; + this.orm = useService("orm"); + this.mapContainerRef = useRef("mapContainer"); + useEffect(() =>{ + if (this.root){ + this.root.dispose() + } + this._Ks_render() + }); + + } + + _Ks_render() { + var self = this; + var rec = this.props.record.data; + if ($(self.mapContainerRef.el).find("div.graph_text").length){ + $(self.mapContainerRef.el).find("div.graph_text").remove(); + } + if (rec.ks_dashboard_item_type === 'ks_map_view'){ + if(rec.ks_data_calculation_type !== "query"){ + if (rec.ks_model_id) { + if (rec.ks_chart_groupby_type == 'date_type' && !rec.ks_chart_date_groupby) { + return $(self.mapContainerRef.el).append($("
").text("Select Group by date to create chart based on date groupby")); + } else if (rec.ks_chart_data_count_type === "count" && !rec.ks_chart_relation_groupby) { + $(self.mapContainerRef.el).append($("
").text("Select Group By to create chart view")); + } else if (rec.ks_chart_data_count_type !== "count" && (rec.ks_chart_measure_field.count === 0 || !rec.ks_chart_relation_groupby)) { + $(self.mapContainerRef.el).append($("
").text("Select Measure and Group By to create chart view")); + } else if (!rec.ks_chart_data_count_type) { + $(self.mapContainerRef.el).append($("
").text("Select Chart Data Count Type")); + } else { + this.get_map_data(rec); + } + } else { + $(self.mapContainerRef.el).append($("
").text("Select a Model first.")); + } + }else if(rec.ks_data_calculation_type === "query" && rec.ks_query_result) { + if(rec.ks_xlabels && rec.ks_ylabels){ + this.get_map_data(rec); + } else { + $(self.mapContainerRef.el).append($("
").text("Please choose the X-labels and Y-labels")); + } + }else { + $(self.mapContainerRef.el).append($("
").text("Please run the appropriate Query")); + } + } + + } + + async get_map_data(rec){ + if($(this.mapContainerRef.el).find(".graph_text").length){ + $(this.mapContainerRef.el).find(".graph_text").remove(); + } + var ks_data=[]; + let data = []; + let label_data = []; + let query_label_data = []; + let domain = []; + var partners; + const chart_data = JSON.parse(this.props.record.data.ks_chart_data); + if (chart_data.groupByIds?.length){ +// domain = [['id', 'in', chart_data.groupByIds]] +// var fields = ["partner_latitude", "partner_longitude", "name"]; +// partners = await this.orm.searchRead("res.partner", domain, fields); + partners = chart_data['partner'] + +// const partners_query = await this._fetchRecordsPartner(rec); + const partners_query = chart_data['ks_partners_map'] + var ks_labels = chart_data['labels']; + var ks_data = chart_data.datasets[0].data; + if (rec.ks_data_calculation_type === 'query'){ + for (let i=0 ; i").text("No Data Available.")); +} +} +// }else{ +// $(this.mapContainerRef.el).append($("
").text("Please select Groupby that has Address"));} +// }; + async _fetchRecordsPartner(data) { + let domain = []; + if (data && data['ks_partners_map']) { + domain = [['id', 'in', JSON.parse(data['ks_partners_map'])]] + } + const fields = ["partner_latitude", "partner_longitude", "name"]; + const records = await this.orm.searchRead("res.partner", domain, fields); + return records + } + +} + +KsMapPreview.template = "KsMapPreview"; + +export const ks_map_preview_field = { + component:KsMapPreview, + supportedTypes : ["char"] +}; + +registry.category("fields").add("ks_dashboard_map_preview", ks_map_preview_field); \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_map_view/ks_map_view.xml b/ks_dashboard_ninja/static/src/widgets/ks_map_view/ks_map_view.xml new file mode 100644 index 000000000..0b6c8e065 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_map_view/ks_map_view.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_new_dashboard_item_theme/ks_theme_component.js b/ks_dashboard_ninja/static/src/widgets/ks_new_dashboard_item_theme/ks_theme_component.js new file mode 100644 index 000000000..9fde3fd09 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_new_dashboard_item_theme/ks_theme_component.js @@ -0,0 +1,33 @@ +/** @odoo-module **/ +import { registry } from "@web/core/registry"; +const { Component} = owl; + +export class KsDashboardTheme extends Component { + setup(){ + var self = this.props; + this.props.colors = ['white','blue','red','yellow','green'] + } + get value(){ + return this.props.record.data[this.props.name] + } + + ks_dashboard_theme_input_container_click(ev) { + var self = this.props; + var $box = $(ev.currentTarget).find(':input'); + if ($box.is(":checked")) { + $('.ks_dashboard_theme_input').prop('checked', false) + $box.prop("checked", true); + } else { + $box.prop("checked", false); + } + this.props.record.update({ [this.props.name]: $box[0].value }); + } + } +KsDashboardTheme.template="Ks_theme"; +export const KsDashboardThemeField = { + component: KsDashboardTheme, + supportedTypes: ["char"], +}; + +registry.category("fields").add('ks_dashboard_item_theme', KsDashboardThemeField); + diff --git a/ks_dashboard_ninja/static/src/widgets/ks_new_dashboard_item_theme/ks_theme_component.xml b/ks_dashboard_ninja/static/src/widgets/ks_new_dashboard_item_theme/ks_theme_component.xml new file mode 100644 index 000000000..fc5fd0773 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_new_dashboard_item_theme/ks_theme_component.xml @@ -0,0 +1,14 @@ + + + +
+ +
+ + +
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.js b/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.js new file mode 100644 index 000000000..84116e135 --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.js @@ -0,0 +1,120 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import {globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions'; +import { getCurrency } from "@web/core/currency"; +import { formatFloat,formatInteger } from "@web/views/fields/formatters"; +import { imageCacheKey } from "@web/views/fields/image/image_field"; +import { url } from "@web/core/utils/urls"; + +const { useEffect, useRef, xml, onWillUpdateProps,Component} = owl; + +class KsItemPreview extends Component { + + file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'} + + setup() { + super.setup(); + const self = this; + } + get value(){ + var self = this; + var field = self.props.record.data; + var item_info; + var ks_rgba_background_color, ks_rgba_font_color, ks_rgba_icon_color; + ks_rgba_background_color = self._get_rgba_format(field.ks_background_color) + ks_rgba_font_color = self._get_rgba_format(field.ks_font_color) + ks_rgba_icon_color = self._get_rgba_format(field.ks_default_icon_color) + item_info = { + name: field.name, + count: globalfunction.ksNumFormatter(field.ks_record_count, 1), + icon_select: field.ks_icon_select, + default_icon: field.ks_default_icon, + icon_color: ks_rgba_icon_color, + count_tooltip: formatFloat(field.ks_record_count, {digits: [0, field.ks_precision_digits]}), + ks_layout : field.ks_layout, + ks_rgba_background_color : self._get_rgba_format(field.ks_background_color), + ks_rgba_font_color : self._get_rgba_format(field.ks_font_color), + ks_rgba_icon_color : self._get_rgba_format(field.ks_default_icon_color), + ks_rgba_dark_background_color_l2 : self._get_rgba_format(self.ks_get_dark_color(field.ks_background_color.split(',')[0], field.ks_background_color.split(',')[1], -10)) + } + + if (field.ks_icon) { + if (!self.isBinSize(field.ks_icon)) { + // Use magic-word technique for detecting image type + item_info['img_src'] = 'data:image/' + (self.file_type_magic_word[field.ks_icon] || 'png') + ';base64,' + field.ks_icon; + } else { + item_info['img_src'] = url('/web/image', { + model: self.env.model.root.resModel, + id: JSON.stringify(this.props.record.evalContext.id), + field: "ks_icon", + // unique forces a reload of the image when the record has been updated + unique: imageCacheKey(field.write_date), + }); + } + + } + if (!field.name) { + if (field.ks_model_name) { + item_info['name'] = field.ks_model_id[1]; + } else { + item_info['name'] = "Name"; + } + } + + if (field.ks_multiplier_active){ + var ks_record_count = field.ks_record_count * field.ks_multiplier + item_info['count'] = globalfunction._onKsGlobalFormatter(ks_record_count, field.ks_data_format, field.ks_precision_digits); + item_info['count_tooltip'] = ks_record_count; + }else{ + item_info['count'] = globalfunction._onKsGlobalFormatter(field.ks_record_count, field.ks_data_format, field.ks_precision_digits); + } + + if (field.ks_unit){ + if (field.ks_multiplier_active){ + var ks_record_count = field.ks_record_count * field.ks_multiplier + }else{ + var ks_record_count = field.ks_record_count + } + var ks_selection = field.ks_unit_selection; + if (ks_selection === 'monetary') { + var ks_currency_id = field.ks_currency_id[0]; + 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'] = ks_data; + } else if (ks_selection === 'custom') { + var ks_field = field.ks_chart_unit; + item_info['count']= ks_field+" "+globalfunction._onKsGlobalFormatter(ks_record_count, field.ks_data_format, field.ks_precision_digits); + }else { + item_info['count']= globalfunction._onKsGlobalFormatter(ks_record_count, field.ks_data_format, field.ks_precision_digits); + } + } + return item_info + } + + isBinSize(value) { + return /^\d+(\.\d*)? [^0-9]+$/.test(value); + } + _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] + ")"; + } + 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; + } + } + + KsItemPreview.template = "ks_tile"; + export const KsItemPreviewfield = { + component :KsItemPreview, + } + registry.category("fields").add('ks_dashboard_item_preview_owl', KsItemPreviewfield); + diff --git a/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.xml b/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.xml new file mode 100644 index 000000000..f5d8afd0b --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_tile/ks_tile.xml @@ -0,0 +1,238 @@ + + + + + + + + + + + + +
+
+ + +
+
+
+ + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+ +
+ + +
+
+ + + + + + + + +
+ +
+
+ +
+
+ +
+ +
+ + + +
+ +
+ +
+ +
+ + +
+
+ + +
+
+
+ + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+ +
+ + +
+
+ + + + + + + + +
+ +
+
+ +
+
+ +
+ +
+ + + +
+
+
+ +
+ + +
+
+ + + + + + + + +
+
+
+ +
+
+ +
+
+
+ + +
+
+ +
+ + +
+
+
+ +
+
+ +
+
+ +
+ + + + + + + + + +
+ + +
+
+
+ +
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.js b/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.js new file mode 100644 index 000000000..5ddd0b27a --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.js @@ -0,0 +1,73 @@ +/** @odoo-module */ + +import { formatDate, parseDateTime } from "@web/core/l10n/dates"; +import { registry } from "@web/core/registry"; + +const { useEffect, useRef, onWillStart ,Component } = owl; + +class KsToDOViewPreview extends Component { + setup() { + super.setup(); + const self = this; + } + + + _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 value() { + const self = this; + var rec = self.props.record.data; + if (rec.ks_dashboard_item_type === 'ks_to_do') { + var ks_header_color = self._ks_get_rgba_format(rec.ks_header_bg_color); + var ks_font_color = self._ks_get_rgba_format(rec.ks_font_color); + var ks_rgba_button_color = self._ks_get_rgba_format(rec.ks_button_color); + var list_to_do_data = {} + if (rec.ks_to_do_data){ + list_to_do_data = JSON.parse(rec.ks_to_do_data) + } + + var item_info ={ + ks_to_do_view_name: rec.name ? rec.name : 'Name', + to_do_view_data: list_to_do_data, + ks_header_color : ks_header_color, + ks_font_color :ks_font_color + + } +// $todoViewContainer.find('.ks_card_header').addClass('ks_bg_to_color').css({"background-color": ks_header_color }); +// $todoViewContainer.find('.ks_card_header').addClass('ks_bg_to_color').css({"color": ks_font_color + ' !important' }); +// $todoViewContainer.find('.ks_li_tab').addClass('ks_bg_to_color').css({"color": ks_font_color + ' !important' }); +// $todoViewContainer.find('.ks_chart_heading').addClass('ks_bg_to_color').css({"color": ks_font_color + ' !important' }); +// $(this.input.el.parentElement).append($todoViewContainer); + } + return item_info + } + ksOnToDoClick(ev){ + ev.preventDefault(); + var self= this; + var tab_id = $(ev.target).attr('href'); + var $tab_section = $('#' + tab_id.substring(1)); + $(ev.target).addClass("active"); + $(ev.target).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.target).parent().parent().siblings().attr('data-section-id', $(ev.target).data().sectionId); + } +} +KsToDOViewPreview.template="ks_to_do_container"; +export const KsToDOViewPreviewfield = { + component:KsToDOViewPreview +} +registry.category("fields").add("ks_dashboard_to_do_preview", KsToDOViewPreviewfield); + diff --git a/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.xml b/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.xml new file mode 100644 index 000000000..fdf243e6c --- /dev/null +++ b/ks_dashboard_ninja/static/src/widgets/ks_to_do/ks_to_do.xml @@ -0,0 +1,176 @@ + + + + +
+
+
+
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ +
+ + +
+
+
+ + +
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + No Tasks Available + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + +
+ + + +
+
+ + No Tasks Available + + +
+
+
+
+
+ +
+ No Tasks Available +
+
+
+
+
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml b/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml new file mode 100644 index 000000000..22687e5c7 --- /dev/null +++ b/ks_dashboard_ninja/static/src/xml/ks_ai_dash_ninja.xml @@ -0,0 +1,96 @@ + + + + + + +
+ +
+ + Here are your generated Items, kindly select to add them in your current dashboard + +
+
+ +
+ + + + + + + + +
+
+ + + + + +
+ +
+ + +
+ + + + + + + +
+
+

+ Your AI dashboard is empty +

+

+ To Generate items with AI, use + + Generate items with AI button + + on top right. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml b/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml new file mode 100644 index 000000000..0b7fdb55f --- /dev/null +++ b/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_item_templates.xml @@ -0,0 +1,19 @@ + + + + + + + +
+

Fields Required : Name, Model, Icon (Default or Custom Upload), Layout

+
+
+ + +
+

Coming Soon in Future :)

+
+
+ +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml b/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml new file mode 100644 index 000000000..3109d6455 --- /dev/null +++ b/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml @@ -0,0 +1,496 @@ + + + + + + +
+ + + +
+ + + + + + + + + + + + + + +
+

Welcome

+
+
+ + +
+ + + + +
+ + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + +
+ +
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + + +
+ + + +
+ +
+ + +
+ + + + + + + +
+
+

+ Your personal dashboard is empty +

+

+ To add dashboard item, use + + Add button + + on top right corner. +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+(ev)=>self.kslayout(ev) + + +
+ + +
+
+ + + + + +
+ + + \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml b/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml new file mode 100644 index 000000000..4f9e8ed55 --- /dev/null +++ b/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml @@ -0,0 +1,97 @@ + + + + +
+ + + + +
+
+ +
+ +
+ + + +
+ +
+
+
+
+
+
+
+ + +
+ + or + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/xml/ks_domain_props.xml b/ks_dashboard_ninja/static/src/xml/ks_domain_props.xml new file mode 100644 index 000000000..9183f0907 --- /dev/null +++ b/ks_dashboard_ninja/static/src/xml/ks_domain_props.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/ks_dashboard_ninja/static/src/xml/ks_quick_edit_view.xml b/ks_dashboard_ninja/static/src/xml/ks_quick_edit_view.xml new file mode 100644 index 000000000..2cf3fb411 --- /dev/null +++ b/ks_dashboard_ninja/static/src/xml/ks_quick_edit_view.xml @@ -0,0 +1,24 @@ + + + +
+
+
+ + +
+
+ +
\ No newline at end of file diff --git a/ks_dashboard_ninja/views/ks_ai_dashboard.xml b/ks_dashboard_ninja/views/ks_ai_dashboard.xml index 5f2f97007..ee6133b0c 100644 --- a/ks_dashboard_ninja/views/ks_ai_dashboard.xml +++ b/ks_dashboard_ninja/views/ks_ai_dashboard.xml @@ -1,46 +1,60 @@ - + ks_dashboard_ninja.arti_int form ks_dashboard_ninja.arti_int -
+
- - Generate items with AI - + Generate items with AI
- + - - + + - - + + + +
-
-
+ +
+ + AI Dashboard ir.actions.act_window @@ -49,5 +63,8 @@ new + +
-
+ + \ No newline at end of file diff --git a/ks_dashboard_ninja/views/ks_dashboard_action.xml b/ks_dashboard_ninja/views/ks_dashboard_action.xml index 681256ee7..465650c4a 100644 --- a/ks_dashboard_ninja/views/ks_dashboard_action.xml +++ b/ks_dashboard_ninja/views/ks_dashboard_action.xml @@ -1,34 +1,34 @@ - - + + ks_dashboard_ninja_item action ks_ninja_dashboard.item_action
- - - + + +
-
-
+ +
+
-
+ \ No newline at end of file diff --git a/ks_dashboard_ninja/views/ks_dashboard_csv_group_by.xml b/ks_dashboard_ninja/views/ks_dashboard_csv_group_by.xml index 6a46ebc73..37f7d8f27 100644 --- a/ks_dashboard_ninja/views/ks_dashboard_csv_group_by.xml +++ b/ks_dashboard_ninja/views/ks_dashboard_csv_group_by.xml @@ -38,4 +38,9 @@ tree,form + + + + + \ No newline at end of file diff --git a/ks_dashboard_ninja/views/ks_dashboard_group_by.xml b/ks_dashboard_ninja/views/ks_dashboard_group_by.xml index ee67979af..9f3296e16 100644 --- a/ks_dashboard_ninja/views/ks_dashboard_group_by.xml +++ b/ks_dashboard_ninja/views/ks_dashboard_group_by.xml @@ -38,5 +38,9 @@ tree,form - + + + + + \ No newline at end of file diff --git a/ks_dashboard_ninja/views/ks_dashboard_ninja_item_view.xml b/ks_dashboard_ninja/views/ks_dashboard_ninja_item_view.xml index 7ac04a323..da049c03b 100644 --- a/ks_dashboard_ninja/views/ks_dashboard_ninja_item_view.xml +++ b/ks_dashboard_ninja/views/ks_dashboard_ninja_item_view.xml @@ -1,8 +1,7 @@ - - + Dashboard Items ks_dashboard_ninja.item @@ -22,523 +21,786 @@ + + dashboard.items.search.view ks_dashboard_ninja.item - + - - + + - + + + ks_dashboard_ninja_item form ks_dashboard_ninja.item 20 -
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + +
- + + ks_dashboard_ninja_item form ks_dashboard_ninja.item 10 -
- + - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Below action will be performed at the end of the Drill Down Action + + + + + + + + + + + + + + + + + + + + + +
+
+
- + + - + Duplicate ir.actions.server code - action = { + + action = { 'name' : 'Dashboard Item Action', 'type': 'ir.actions.act_window', 'context': {'default_ks_dashboard_item_ids': records.ids, 'default_ks_action':'duplicate'}, @@ -546,17 +808,20 @@ 'res_model': 'ks_ninja_dashboard.item_action', 'views': [(env.ref('ks_dashboard_ninja.ks_dashboard_ninja_action').id, 'form')], 'target':'new' - } + } + + - + Move ir.actions.server code form - action = { + + action = { 'type': 'ir.actions.act_window', 'name' : 'Dashboard Item Action', 'context': {'default_ks_dashboard_item_ids': records.ids, 'default_ks_action':'move'}, @@ -564,12 +829,15 @@ 'res_model': 'ks_ninja_dashboard.item_action', 'views': [(env.ref('ks_dashboard_ninja.ks_dashboard_ninja_action').id, 'form')], 'target':'new' - } + } + - + + Dashboard Items ks_dashboard_ninja.item tree,form - + + \ No newline at end of file diff --git a/ks_dashboard_ninja/views/ks_dashboard_ninja_view.xml b/ks_dashboard_ninja/views/ks_dashboard_ninja_view.xml index 9b72a9330..85d6261f3 100644 --- a/ks_dashboard_ninja/views/ks_dashboard_ninja_view.xml +++ b/ks_dashboard_ninja/views/ks_dashboard_ninja_view.xml @@ -1,30 +1,33 @@ - - + + ks_dashboard_ninja View ks_dashboard_ninja.board -
+ - - - + + + + + readonly ="(id > 0)" required="(id <= 1)" + options="{'no_create': True, 'no_create_edit':True, 'no_open': True}"/> + + readonly="(ks_dashboard_state == 'Locked')" + required="(ks_dashboard_state != 'Locked')" + /> - + @@ -33,12 +36,13 @@ - + - - - + + + @@ -64,54 +68,63 @@ + readonly="(ks_date_filter_selection != 'l_custom')" + required ="(ks_date_filter_selection == 'l_custom')"/> + readonly="(ks_date_filter_selection != 'l_custom')" + required ="(ks_date_filter_selection == 'l_custom')"/> - + -
+ +
- + + ks_dashboard_ninja View ks_dashboard_ninja.board - - + + + + + - + - + options="{'no_create': True, 'no_create_edit':True, 'no_open': True}" readonly="(ks_dashboard_state == 'Locked')" + required="(ks_dashboard_state != 'Locked')"/> + + readonly ="(id > 0)" required="(id <= 1)" + options="{'no_create': True, 'no_create_edit':True, 'no_open': True}"/> + readonly="(ks_date_filter_selection != 'l_custom')" + required ="(ks_date_filter_selection == 'l_custom')" + /> + readonly="(ks_date_filter_selection != 'l_custom')" + required ="(ks_date_filter_selection == 'l_custom')" + /> -
+
+
+ + +
+
diff --git a/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz.py b/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz.py index cce59d83b..ad6d20bf9 100644 --- a/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz.py +++ b/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz.py @@ -38,11 +38,12 @@ class KSCreateDashboardWizard(models.TransientModel): 'ks_dashboard_top_menu_id': self.ks_top_menu_id.id, }) context = {'ks_reload_menu': True, 'ks_menu_id': ks_create_record.ks_dashboard_menu_id.id} - return { - 'type': 'ir.actions.client', - 'name': "Dashboard Ninja", - 'res_model': 'ks_dashboard_ninja.board', - 'params': {'ks_dashboard_id': ks_create_record.id}, - 'tag': 'ks_dashboard_ninja', - # 'context': self.with_context(context)._context - } + return {'type': 'ir.actions.client', 'tag': 'reload'} + # return { + # 'type': 'ir.actions.client', + # 'name': "Dashboard Ninja", + # 'res_model': 'ks_dashboard_ninja.board', + # 'params': {'ks_dashboard_id': ks_create_record.id}, + # 'tag': 'ks_dashboard_ninja', + # # 'context': self.with_context(context)._context + # } diff --git a/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz_view.xml b/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz_view.xml index f4cd0826a..d8dcecd05 100644 --- a/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz_view.xml +++ b/ks_dashboard_ninja/wizard/ks_create_dashboard_wiz_view.xml @@ -16,23 +16,53 @@ -

- Preview -

- # - # - # - # - # - # - # + +

Preview

+ + # + + # + + # + + # + + # + + # + + # +
-
+ Create Dashboard ir.actions.act_window diff --git a/ks_dashboard_ninja/wizard/ks_duplicate_dashboard_wiz.py b/ks_dashboard_ninja/wizard/ks_duplicate_dashboard_wiz.py index 23963acd2..2b0f31084 100644 --- a/ks_dashboard_ninja/wizard/ks_duplicate_dashboard_wiz.py +++ b/ks_dashboard_ninja/wizard/ks_duplicate_dashboard_wiz.py @@ -24,8 +24,15 @@ class KSduplicateDashboardWizard(models.TransientModel): dup_dash = self.env['ks_dashboard_ninja.board'].browse(dashboard_id).copy({'ks_dashboard_top_menu_id': self.ks_top_menu_id.id}) context = {'ks_reload_menu': True, 'ks_menu_id': dup_dash.ks_dashboard_menu_id.id} dash_id = self.env['ks_dashboard_ninja.board'].browse(dashboard_id) - if not dup_dash.ks_dashboard_items_ids: + length_to_skip = len(dup_dash.ks_dashboard_items_ids.ids) + + count = 0 + + if dup_dash.ks_dashboard_items_ids or length_to_skip == 0: for item in dash_id.ks_dashboard_items_ids: + if count < length_to_skip: + count += 1 + continue item.sudo().copy({'ks_dashboard_ninja_board_id': dup_dash.id}) return { 'type': 'ir.actions.client', @@ -38,24 +45,10 @@ class KSDeleteDashboardWizard(models.TransientModel): _description = 'Dashboard Delete Wizard' - def DeleteDashBoard(self): - '''this function returns acion id of ks.dashboard.delete.wizard''' - action = self.env['ir.actions.act_window']._for_xml_id( - 'ks_dashboard_ninja.ks_delete_dashboard_wizard') - action['context'] = {'dashboard_id': self.id} - return action - - def ks_delete_record(self): + def ks_delete_record(self, **kwargs): '''this function creats record of ks_dashboard_ninja.board and return dashboard action_id''' - dashboard_id = self._context.get('dashboard_id') + dashboard_id = kwargs.get('dashboard_id') self.env['ks_dashboard_ninja.board'].browse(dashboard_id).unlink() - # context = {'ks_reload_menu': True, 'ks_menu_id': self.env['ir.ui.menu'].search([('name', '=', 'My Dashboard')], limit=1).id} - return { - 'type': 'ir.actions.client', - 'name': "Dashboard Ninja", - 'res_model': 'ks_dashboard_ninja.board', - 'params': {'ks_dashboard_id': 1}, - 'tag': 'ks_dashboard_ninja', - # 'context': self.with_context(context)._context - } - + action = self.env['ir.actions.client']._for_xml_id( + 'ks_dashboard_ninja.board_dashboard_action_window') + return action diff --git a/yuthon_holiday/models/inherit_hr_leave.py b/yuthon_holiday/models/inherit_hr_leave.py index 7f0367f22..fc6dfe42a 100644 --- a/yuthon_holiday/models/inherit_hr_leave.py +++ b/yuthon_holiday/models/inherit_hr_leave.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -from datetime import datetime, timedelta +from datetime import datetime, timedelta, time + from odoo import models, fields, api, _ from odoo.exceptions import ValidationError @@ -59,7 +60,7 @@ class HolidaysRequestBatch(models.Model): text = fields.Html(string='申请事由') leave_line_ids = fields.One2many('hr.leave.line', 'leave_batch_id', string="关联请假详情明细行") is_issues = fields.Boolean(string='是否上会') - leave_by_hour = fields.Boolean(string='按小时请假', default=False) + leave_by_hour = fields.Boolean(string='按小时请假', default=True) leave_unit = fields.Selection(string='时长单位', selection=[('day', '天'), ('hour', '小时')]) @api.constrains('leave_line_ids') @@ -72,7 +73,8 @@ class HolidaysRequestBatch(models.Model): @api.onchange('leave_by_hour') def _onchange_leave_by_hour(self): - self.leave_unit = 'hour' if self.leave_by_hour else 'day' + # self.leave_unit = 'hour' if self.leave_by_hour else 'day' + self.leave_unit = 'day' self.leave_line_ids = None # 提交 @@ -155,9 +157,11 @@ class HrLeaveLine(models.Model): 按小时请假时不能跨天 """ for rec in self: - if rec.leave_batch_id.leave_by_hour: - if rec.start_time != rec.end_time: - raise ValidationError('按小时请假禁止跨天') + if rec.start_time > rec.end_time: + raise ValidationError('开始时间不能大于结束时间') + # if rec.leave_batch_id.leave_by_hour: + # if rec.start_time != rec.end_time: + # raise ValidationError('按小时请假禁止跨天') @api.depends('leave_type_id') def _compute_available_days(self): @@ -182,7 +186,22 @@ class HrLeaveLine(models.Model): end_time_obj = datetime.strptime(hour_selection[record.end_hour_from], "%H:%M").time() start_date = datetime.combine(record.start_time, start_time_obj) end_time = datetime.combine(record.end_time, end_time_obj) - leave_duration = (end_time - start_date).total_seconds() / 3600 + # 根据时间段计算请假时长 + # 天数计算公式,每天最大时长为8,如果请假时间超过8,则按8计算,小于8,则按请假时间计算 + # 如果有跨天 + # 天数 = 第一天的天数 + 间隔时常 - 2天 + 最后一天的天数 + first_days, interval_days, last_days = 0, 0, 0 + # 跨天 + if start_date.date() != end_time.date(): + # 第一天的天数, 如果开始时间大于中午十二点,则按0.5计算,如果小于中午十二点,则按1天计算 + first_days = (start_date.time() > time(12, 0)) and 0.5 or 1 + interval_days = (end_time.date() - start_date.date()).days - 2 + last_days = (end_time.time() > time(12, 0)) and 0.5 or 1 + # 没有跨天 + else: + # 天数 = 时常 / 8 + first_days = (end_time - start_date).total_seconds() / 3600 / 8 + leave_duration = first_days + interval_days + last_days else: start_date = datetime.combine(record.start_time, datetime.min.time()) end_time = datetime.combine(record.end_time, datetime.min.time()) @@ -194,14 +213,16 @@ class HrLeaveLine(models.Model): for record in self: # 如果假期类型需要分配 if record.leave_type_id.requires_allocation == 'yes': - record.residual = record.available_days - record.residual + record.residual = record.available_days - record.leave_duration else: record.residual = 0 @api.onchange('start_time', 'start_hour_from', 'end_time', 'end_hour_from') def _onchange_leave_date(self): - if self.leave_batch_id.leave_by_hour and self.start_time and self.end_time and self.start_time != self.end_time: - raise ValidationError('按小时请假禁止跨天') + if self.start_time > self.end_time: + raise ValidationError('开始时间不能大于结束时间') + # if self.leave_batch_id.leave_by_hour and self.start_time and self.end_time and self.start_time != self.end_time: + # raise ValidationError('按小时请假禁止跨天') # 计算开始时间与结束时间之间的时长 def _get_leave_duration(self, start_time: datetime, end_time: datetime): diff --git a/yuthon_holiday/models/inherit_hr_leave_allocation.py b/yuthon_holiday/models/inherit_hr_leave_allocation.py index d5e6f6f37..550b0bca1 100644 --- a/yuthon_holiday/models/inherit_hr_leave_allocation.py +++ b/yuthon_holiday/models/inherit_hr_leave_allocation.py @@ -3,30 +3,89 @@ from odoo import models, fields, api class HrLeaveAllocation(models.Model): - _inherit = 'hr.leave.allocation' - - holiday_type = fields.Selection([ - ('employee', '按员工角色'), - ('company', 'By Company'), - ('department', 'By Department'), - ('category', 'By Employee Tag')], - string='模式', readonly=False, required=True, default='employee') - users_role_ids = fields.Many2many('soong.user.role', string='角色范围') - new_employee_holidays = fields.Selection([('limit', '限制'), ('un_limit', '不限制')], string="新员工请假") - holiday_month = fields.Selection(selection=[(str(i), str(i)) for i in range(1, 13)], string="入职月份", help='入职时长小于此月份时,不可申请此假期') - holiday_expiration_date = fields.Selection([('never', '永久'), ('no_never', '不固定')], string="新员工请假") - start_time = fields.Date(string="开始时间") - end_time = fields.Date(string="结束时间") - @api.onchange('users_role_ids') - def onchange_employee_ids(self): - users_role_list = [] - for i in self.users_role_ids: - user_role_data = self.env['hr.employee'].search(['|', ('user_role_id', '=', i.id.origin), ('user_role_ids', '=', i.id.origin)]) - users_role_list += [ro.user_id.id for ro in user_role_data] - if self.users_role_ids: - false_none_list = [x for x in users_role_list if x != False] - self.employee_ids = [(6, 0, list(set(false_none_list)))] - + _inherit = 'hr.leave.allocation' + holiday_type = fields.Selection([ + ('employee', '按员工角色'), + ('company', 'By Company'), + ('department', 'By Department'), + ('category', 'By Employee Tag')], + string='模式', readonly=False, required=True, default='employee') + # users_role_ids = fields.Many2many('soong.user.role', string='角色范围') + new_employee_holidays = fields.Selection([('limit', '限制'), ('un_limit', '不限制')], string="新员工请假") + holiday_month = fields.Selection(selection=[(str(i), str(i)) for i in range(1, 13)], string="入职月份", + help='入职时长小于此月份时,不可申请此假期') + holiday_expiration_date = fields.Selection([('never', '永久'), ('no_never', '不固定')], string="新员工请假") + start_time = fields.Date(string="开始时间") + end_time = fields.Date(string="结束时间") + @api.onchange('users_role_ids') + def onchange_employee_ids(self): + users_role_list = [] + for i in self.users_role_ids: + user_role_data = self.env['hr.employee'].search(['|', ('user_role_id', '=', i.id.origin), ('user_role_ids', '=', i.id.origin)]) + users_role_list += [ro.user_id.id for ro in user_role_data] + if self.users_role_ids: + false_none_list = [x for x in users_role_list if x != False] + self.employee_ids = [(6, 0, list(set(false_none_list)))] + def _action_validate_create_childs(self): + """ + 验证分配方案,根据应计方案创建对应用户的年假分配方案 + @return: + """ + allocation_vals = [] + for allocation in self: + if allocation.allocation_type == 'accrual' and allocation.accrual_plan_id: + # 根据应计方案创建对应用户的年假分配方案 + if ( + allocation.state == 'validate' + and ( + allocation.holiday_type in ['category', 'department', 'company'] + or (allocation.holiday_type == 'employee' and len(allocation.employee_ids) > 1) + ) + ): + if allocation.holiday_type == 'employee': + employees = allocation.employee_ids + elif allocation.holiday_type == 'category': + employees = allocation.category_id.employee_ids + elif allocation.holiday_type == 'department': + employees = allocation.department_id.member_ids + else: + employees = self.env['hr.employee'].search([('company_id', '=', allocation.mode_company_id.id)]) + # {员工社保时间: 员工列表} + emp_dict = {} + # 员工根据社保时间创建字典 + for e in employees: + # [XSK] TODO 使用实际字段 -2024/11/15 17:00 + key = e.children + if emp_dict.get(key): + emp_dict[key].append(e) + else: + emp_dict[key] = [e] + # 将里程节点按照时间从大到小排序,满足一个以后跳出循环 + plan_level = allocation.accrual_plan_id.level_ids.sorted(key=lambda x: x.added_value, reverse=True) + for level in plan_level: + # 员工字段单位是月,应计方案雇员累计单位不确定 + # added_value_type 为 day, hour 通通转换为月 + level_month = 0 + if level.added_value_type == 'day': + level_month = level.added_value // 30 + if level.added_value_type == 'hour': + level_month = level.added_value // (30 * 24) + for emp_int, emp_list in emp_dict.items(): + if emp_int >= level_month: + # [XSK] TODO(2024/11/15): + # 应计方案内时间支持天月年,不支持小时 + # 在请求类型中应该只支持小时 + info_list = [{**item, 'number_of_days': level.start_count} for item in allocation._prepare_holiday_values(emp_list)] + allocation_vals.extend(info_list) + break + else: + super()._action_validate_create_childs() + if allocation_vals: + self.env['hr.leave.allocation'].with_context( + mail_notify_force_send=False, + mail_activity_automation_skip=True + ).create(allocation_vals) + self.linked_request_ids.filtered(lambda c: c.state != 'validate').action_validate() diff --git a/yuthon_holiday/models/inherit_hr_leave_type.py b/yuthon_holiday/models/inherit_hr_leave_type.py index 99b154dc9..9c0b1255d 100644 --- a/yuthon_holiday/models/inherit_hr_leave_type.py +++ b/yuthon_holiday/models/inherit_hr_leave_type.py @@ -8,4 +8,4 @@ class HrLeaveType(models.Model): leave_documents_id = fields.Many2many('ir.attachment', string="假期详细说明") available_days = fields.Integer(string="可用天数") is_one = fields.Boolean(string="是否一次性休完") - allocation_validation_type = fields.Selection(defalt='no') \ No newline at end of file + allocation_validation_type = fields.Selection(defalt='no') diff --git a/yuthon_holiday/views/hr_leave_batch.xml b/yuthon_holiday/views/hr_leave_batch.xml index 9abd77bd1..0a2b44623 100644 --- a/yuthon_holiday/views/hr_leave_batch.xml +++ b/yuthon_holiday/views/hr_leave_batch.xml @@ -94,8 +94,8 @@ - + diff --git a/yuthon_holiday/views/inherit_hr_leave_allocation_views.xml b/yuthon_holiday/views/inherit_hr_leave_allocation_views.xml index 9282d8a19..5d8b3ea47 100644 --- a/yuthon_holiday/views/inherit_hr_leave_allocation_views.xml +++ b/yuthon_holiday/views/inherit_hr_leave_allocation_views.xml @@ -5,26 +5,6 @@ hr.leave.allocation - - bottom - - - 假期余额 - - - hide - - - 开始时间 - show - - - 结束时间 - show - - - bottom - 假期余额 @@ -33,13 +13,10 @@ 开始时间 - show 结束时间 - show - @@ -48,7 +25,7 @@ - + diff --git a/yuthon_hr_attendance/models/planning_template_inherit.py b/yuthon_hr_attendance/models/planning_template_inherit.py index 0a8f2d2e5..6054f1e18 100644 --- a/yuthon_hr_attendance/models/planning_template_inherit.py +++ b/yuthon_hr_attendance/models/planning_template_inherit.py @@ -37,3 +37,61 @@ class PlanningTemplate(models.Model): end_datetime = start_datetime + timedelta(hours=hours, minutes=minutes) duration_days = math.ceil((end_datetime - start_datetime).total_seconds() / (3600 * 24)) return duration_days, timedelta(hours=end_datetime.hour, minutes=end_datetime.minute).total_seconds() / 3600 + + +class Planning(models.Model): + _inherit = 'planning.slot' + + # 修改原生自动安排函数 + @api.model + def auto_plan_ids(self, view_domain): + """ + 判断今天的班次是否存在,如果不存在则自动分配班次 + @param view_domain: 当前视图显示的时间区间 + @return: + """ + # 获取当前时区 + user_tz = pytz.timezone(self.env.user.tz or 'UTC') + # 根据时区获取当天的0分0秒并转换成UTC时间 + today = datetime.now(tz=user_tz) + tz_start_datetime = user_tz.localize(datetime.combine(today, time(hour=0, minute=0, second=0))) + tz_end_datetime = user_tz.localize(datetime.combine(today, time(hour=23, minute=59, second=59))) + utc_start_datetime = tz_start_datetime.astimezone(pytz.utc) + utc_end_datetime = tz_end_datetime.astimezone(pytz.utc) + # 查询当天所有的班次, 区间在今天内,或者开始时间在今天的 + planning_slot = self.search([ + '|', + '&', + ('start_datetime', '>=', utc_start_datetime), + ('end_datetime', '<=', utc_end_datetime), + '&', + ('start_datetime', '<=', utc_end_datetime), + ('end_datetime', '>=', utc_end_datetime), + ]) + # 将已经存在的班次根据时间形成字典,方便查询 + planning_slot_dict = {} + for ps in planning_slot: + s_time = ps.start_datetime.strftime("%Y-%m-%d %H:%M:%S") + e_time = ps.end_datetime.strftime("%Y-%m-%d %H:%M:%S") + key = f'{s_time}_{e_time}_{ps.role_id.id}_{ps.resource_id.id}' + planning_slot_dict[key] = ps + + # 查询所有班次模板planning.slot.template + planning_slot_temp = self.env['planning.slot.template'].search([]) + create_list = [] + for temp in planning_slot_temp: + if temp.role_id: + s_time = tz_start_datetime.replace(hour=int(temp.start_time), minute=round(math.modf(temp.start_time)[0] / (1 / 60.0))).astimezone(pytz.utc) + e_time = tz_start_datetime.replace(hour=int(temp.end_time), minute=round(math.modf(temp.end_time)[0] / (1 / 60.0))).astimezone(pytz.utc) + if temp.end_time < temp.start_time: + e_time = e_time + timedelta(days=1) + for resource in temp.role_id.resource_ids: + key = f'{s_time.strftime("%Y-%m-%d %H:%M:%S")}_{e_time.strftime("%Y-%m-%d %H:%M:%S")}_{temp.role_id.id}_{resource.id}' + if not planning_slot_dict.get(key): + create_list.append({ + 'start_datetime': s_time.strftime('%Y-%m-%d %H:%M:%S'), + 'end_datetime': e_time.strftime('%Y-%m-%d %H:%M:%S'), + 'role_id': temp.role_id.id, + 'resource_id': resource.id, + }) + return self.create(create_list).ids diff --git a/yuthon_sale_renting/__init__.py b/yuthon_sale_renting/__init__.py deleted file mode 100644 index cde864bae..000000000 --- a/yuthon_sale_renting/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- - -from . import models diff --git a/yuthon_sale_renting/__manifest__.py b/yuthon_sale_renting/__manifest__.py deleted file mode 100644 index d47ab333b..000000000 --- a/yuthon_sale_renting/__manifest__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -{ - 'name': "Yuthon Sale Renting", - 'summary': "物业租赁拓展", - 'description': """ - - """, - 'author': 'pengyuthon', - 'website': 'https://www.pengyuthon.com', - 'category': 'Human Resources/Attendances', - 'version': '0.1', - 'license': 'LGPL-3', - 'depends': ['base', 'sale_renting', 'mail', 'documents', 'soong_workflow', 'contacts'], - 'data': [ - 'data/sale_renting_code_data.xml', - 'security/ir.model.access.csv', - 'views/yuthon_res_partner_views.xml', - 'views/contacts_inherit_menu_views.xml', - ], - 'installable': True, - 'application': True, -} diff --git a/yuthon_sale_renting/models/__init__.py b/yuthon_sale_renting/models/__init__.py deleted file mode 100644 index 9b1f57333..000000000 --- a/yuthon_sale_renting/models/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- - -from . import yuthon_res_partner - - diff --git a/yuthon_sale_renting/models/yuthon_res_partner.py b/yuthon_sale_renting/models/yuthon_res_partner.py deleted file mode 100644 index 9fc3a712a..000000000 --- a/yuthon_sale_renting/models/yuthon_res_partner.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import models, fields, api, exceptions, _ - - -class ResPartner(models.Model): - _inherit = 'res.partner' - _description = '联系人客户字段增加' - - partner_type = fields.Selection([('tenant', '承租方'), ('employee', '员工'), ('company', '公司')], string="客户类型") - - juridical_person = fields.Char(string="法人") - tenant_user_card = fields.Char(string="身份证") - tenant_scope = fields.Char(string="经营范围") - tenant_start_time = fields.Datetime(string="生效日期") - tenant_end_time = fields.Datetime(string="失效日期") - - billing_name = fields.Char(string="开票名称") - billing_type = fields.Char(string="开票类型") - - partner_name = fields.Char(string="联系人") - partner_address = fields.Char(string="送达地址") - partner_type2 = fields.Char(string="承租方类型") - - cell_phone = fields.Char(string='座机') - tax_number = fields.Char(string='税号') - tenant_industry = fields.Many2one('res.partner.industry', string='行业') - - - - - diff --git a/yuthon_sale_renting/security/ir.model.access.csv b/yuthon_sale_renting/security/ir.model.access.csv deleted file mode 100644 index d7595f820..000000000 --- a/yuthon_sale_renting/security/ir.model.access.csv +++ /dev/null @@ -1,4 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink - - - diff --git a/yuthon_sale_renting/static/description/icon.png b/yuthon_sale_renting/static/description/icon.png deleted file mode 100644 index 152b06187..000000000 Binary files a/yuthon_sale_renting/static/description/icon.png and /dev/null differ diff --git a/yuthon_sale_renting/static/description/icon.svg b/yuthon_sale_renting/static/description/icon.svg deleted file mode 100644 index 8f4fe1ba3..000000000 --- a/yuthon_sale_renting/static/description/icon.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/yuthon_sale_renting/views/contacts_inherit_menu_views.xml b/yuthon_sale_renting/views/contacts_inherit_menu_views.xml deleted file mode 100644 index 9575665c5..000000000 --- a/yuthon_sale_renting/views/contacts_inherit_menu_views.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - 公司 - res.partner - kanban,tree,form,activity - - {'default_is_company': True} - [('partner_type', '=', 'company')] - - - 员工 - res.partner - kanban,tree,form,activity - - [('partner_type', '=', 'employee')] - {'default_is_company': True} - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/yuthon_sale_renting/views/yuthon_res_partner_views.xml b/yuthon_sale_renting/views/yuthon_res_partner_views.xml deleted file mode 100644 index 37c874f2a..000000000 --- a/yuthon_sale_renting/views/yuthon_res_partner_views.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - yuthon.res.partner.views.form - res.partner - - - - - - - - - - - - - - - - - - - - - - yuthon.res.partner.views.tree - res.partner - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/yuthon_will_task/models/yuthon_will_task.py b/yuthon_will_task/models/yuthon_will_task.py index 3e4940bbc..d28151b35 100644 --- a/yuthon_will_task/models/yuthon_will_task.py +++ b/yuthon_will_task/models/yuthon_will_task.py @@ -1,18 +1,20 @@ from odoo import api, fields, models, modules import datetime -class YuthonWillTask(models.Model): - _name = 'yuthon.will.task' - _description = '待办' - _rec_name = 'task_content' - priority = fields.Selection([('general', '一般'), ('important', '重要'), ('urgent', '紧急'), ('very_urgent', '非常紧急')], string='优先级') - task_type = fields.Many2one('task.type.setting', string='任务类型') - task_content = fields.Text(string='任务内容') - remarks = fields.Text(string='备注') - creation_time = fields.Date(string='创建时间') - employee_ids = fields.Many2many('hr.employee', string='人员',default=lambda self: self.env.user.employee_id) - remind = fields.Selection([('fifteen','提醒-15分钟'), ('thirty','提醒-30分钟'), ('one_hour','提醒-1小时'), - ('two_hour','提醒-2小时'), ('one_day','提醒-1天')], string='提醒') - start_time = fields.Datetime(string='开始时间') - end_time = fields.Datetime(string='结束时间') +class YuthonWillTask(models.Model): + _name = 'yuthon.will.task' + _description = '待办' + _rec_name = 'task_content' + + priority = fields.Selection([('general', '不紧急不重要'), ('important', '重要不紧急'), + ('urgent', '紧急不重要'), ('very_urgent', '重要且紧急')], string='优先级') + task_type = fields.Many2one('task.type.setting', string='任务类型') + task_content = fields.Text(string='任务内容') + remarks = fields.Text(string='备注') + creation_time = fields.Date(string='创建时间') + employee_ids = fields.Many2many('hr.employee', string='人员', default=lambda self: self.env.user.employee_id) + remind = fields.Selection([('fifteen', '提醒-15分钟'), ('thirty', '提醒-30分钟'), ('one_hour', '提醒-1小时'), + ('two_hour', '提醒-2小时'), ('one_day', '提醒-1天')], string='提醒') + start_time = fields.Datetime(string='开始时间') + end_time = fields.Datetime(string='结束时间')