diff --git a/addons/ks_dashboard_ninja/__init__.py b/addons/ks_dashboard_ninja/__init__.py deleted file mode 100644 index 728ad5d..0000000 --- a/addons/ks_dashboard_ninja/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -from . import models -from . import controllers -from . import common_lib -from . import wizard - -from odoo.api import Environment, SUPERUSER_ID - - -def uninstall_hook(env): - # env = Environment(cr, SUPERUSER_ID, {}) - for rec in env['ks_dashboard_ninja.board'].search([]): - rec.ks_dashboard_client_action_id.unlink() - rec.ks_dashboard_menu_id.unlink() diff --git a/addons/ks_dashboard_ninja/__manifest__.py b/addons/ks_dashboard_ninja/__manifest__.py deleted file mode 100644 index 7cb159b..0000000 --- a/addons/ks_dashboard_ninja/__manifest__.py +++ /dev/null @@ -1,191 +0,0 @@ -# -*- coding: utf-8 -*- -{ - 'name': 'Dashboard Ninja with AI', - - 'summary': """ -Ksolves Dashboard Ninja gives you a wide-angle view of your business that you might have missed. Get smart visual data with interactive and engaging dashboards for your Odoo ERP. Odoo Dashboard, CRM Dashboard, Inventory Dashboard, Sales Dashboard, Account Dashboard, Invoice Dashboard, Revamp Dashboard, Best Dashboard, Odoo Best Dashboard, Odoo Apps Dashboard, Best Ninja Dashboard, Analytic Dashboard, Pre-Configured Dashboard, Create Dashboard, Beautiful Dashboard, Customized Robust Dashboard, Predefined Dashboard, Multiple Dashboards, Advance Dashboard, Beautiful Powerful Dashboards, Chart Graphs Table View, All In One Dynamic Dashboard, Accounting Stock Dashboard, Pie Chart Dashboard, Modern Dashboard, Dashboard Studio, Dashboard Builder, Dashboard Designer, Odoo Studio. Revamp your Odoo Dashboard like never before! It is one of the best dashboard odoo apps in the market. -""", - - 'description': """ -Dashboard Ninja v18.0, - Odoo Dashboard, - Dashboard, - Dashboards, - Odoo apps, - Dashboard app, - HR Dashboard, - Sales Dashboard, - inventory Dashboard, - Lead Dashboard, - Opportunity Dashboard, - CRM Dashboard, - POS, - POS Dashboard, - Connectors, - Web Dynamic, - Report Import/Export, - Date Filter, - HR, - Sales, - Theme, - Tile Dashboard, - Dashboard Widgets, - Dashboard Manager, - Debranding, - Customize Dashboard, - Graph Dashboard, - Charts Dashboard, - Invoice Dashboard, - Project management, - ksolves, - ksolves apps, - Ksolves India Ltd. - Ksolves India Limited, - odoo dashboard apps - odoo dashboard app - odoo dashboard module - odoo modules - dashboards - powerful dashboards - beautiful odoo dashboard - odoo dynamic dashboard - all in one dashboard - multiple dashboard menu - odoo dashboard portal - beautiful odoo dashboard - odoo best dashboard - dashboard for management - Odoo custom dashboard - odoo dashboard management - odoo dashboard apps - create odoo dashboard - odoo dashboard extension - odoo dashboard module -""", - - 'author': 'Ksolves India Ltd.', - - 'license': 'OPL-1', - - 'currency': 'EUR', - - 'price': '518.62', - - 'website': 'https://store.ksolves.com/', - - 'maintainer': 'Ksolves India Ltd.', - - 'live_test_url': 'https://ksdndemo18.kappso.com/web/demo_login', - - 'category': 'Services', - 'version': '18.0.1.1.7', - - 'support': 'sales@ksolves.com', - - 'images': ['static/description/output.gif'], - - 'depends': ['base', 'web', 'base_setup', 'bus', 'base_geolocalize', 'mail'], - - 'data': [ - 'security/ir.model.access.csv', - 'security/ks_security_groups.xml', - 'data/ks_default_data.xml', - 'data/ks_mail_cron.xml', - 'data/dn_data.xml', - 'data/sequence.xml', - 'views/res_settings.xml', - 'views/ks_dashboard_ninja_view.xml', - 'views/ks_dashboard_ninja_item_view.xml', - 'views/ks_dashboard_group_by.xml', - 'views/ks_dashboard_csv_group_by.xml', - 'views/ks_dashboard_action.xml', - 'views/ks_import_dashboard_view.xml', - 'wizard/ks_create_dashboard_wiz_view.xml', - 'wizard/ks_duplicate_dashboard_wiz_view.xml', - 'views/ks_ai_dashboard.xml', - 'views/ks_whole_ai_dashboard.xml', - 'views/ks_key_fetch.xml', - 'views/webExtend.xml' - ], - - 'demo': ['demo/ks_dashboard_ninja_demo.xml'], - - 'assets': { - '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': [ - 'web/static/lib/jquery/jquery.js', - 'ks_dashboard_ninja/static/src/scss/variable.scss', - '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/src/css/ks_dashboard_ninja_pro.css', - 'ks_dashboard_ninja/static/src/css/ks_to_do_item.css', - 'ks_dashboard_ninja/static/src/scss/common.scss', - '/ks_dashboard_ninja/static/src/scss/explainAi.scss', - '/ks_dashboard_ninja/static/src/scss/chat_with_ai.scss', - '/ks_dashboard_ninja/static/src/scss/Generate-ai.scss', - '/ks_dashboard_ninja/static/src/scss/ks_ai_dashboard.scss', - 'ks_dashboard_ninja/static/src/css/style.css', - '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_global_functions.js', - 'ks_dashboard_ninja/static/lib/js/xy.js', - 'ks_dashboard_ninja/static/lib/js/radar.js', - 'ks_dashboard_ninja/static/src/js/domainfix.js', - 'ks_dashboard_ninja/static/src/js/chart_buttons_patch.js', - '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/**/*', - 'ks_dashboard_ninja/static/src/js/charts_render_global_functions.js', - 'ks_dashboard_ninja/static/src/js/cookies.js', - 'ks_dashboard_ninja/static/src/scss/form_views.scss', - 'ks_dashboard_ninja/static/src/scss/modal.scss', - 'ks_dashboard_ninja/static/src/odoo_base_extend/**/*', - ], - }, - - 'external_dependencies': { - 'python': ['pandas', 'xlrd', 'openpyxl', 'gTTS', 'SQLAlchemy'] - }, - - 'uninstall_hook': 'uninstall_hook', -} diff --git a/addons/ks_dashboard_ninja/common_lib/__init__.py b/addons/ks_dashboard_ninja/common_lib/__init__.py deleted file mode 100644 index 2da4c12..0000000 --- a/addons/ks_dashboard_ninja/common_lib/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import ks_date_filter_selections -from . import filter_tools diff --git a/addons/ks_dashboard_ninja/common_lib/filter_tools.py b/addons/ks_dashboard_ninja/common_lib/filter_tools.py deleted file mode 100644 index 4510ae5..0000000 --- a/addons/ks_dashboard_ninja/common_lib/filter_tools.py +++ /dev/null @@ -1,20 +0,0 @@ -import json - -from odoo.tools.safe_eval import safe_eval - - -def replace_company_domain(domain, company_id, company_ids): - domain = safe_eval(domain) if isinstance(domain, str) else domain - new_domain = [] - for condition in domain: - if isinstance(condition, tuple) and len(condition) >= 3: - if condition[1] in ('in', 'not in') and isinstance(condition[2], list) and '%MYCOMPANY' in condition[2]: - new_condition = (condition[0], condition[1], [y for x in condition[2] for y in (company_ids if x == '%MYCOMPANY' else [x])]) - elif condition[2] == '%MYCOMPANY': - new_condition = (condition[0], condition[1], company_id) - else: - new_condition = condition - new_domain.append(new_condition) - else: - new_domain.append(condition) - return json.dumps(new_domain) \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py b/addons/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py deleted file mode 100644 index 4ec7040..0000000 --- a/addons/ks_dashboard_ninja/common_lib/ks_date_filter_selections.py +++ /dev/null @@ -1,343 +0,0 @@ -# -*- coding: utf-8 -*- - -import json -import os -import os.path -from datetime import timedelta - -import pytz -from dateutil import rrule -from dateutil.relativedelta import relativedelta -from odoo import _ -from odoo.exceptions import ValidationError -from odoo.fields import datetime -from odoo.tools.safe_eval import safe_eval - - -def ks_get_date(ks_date_filter_selection, self, type): - try: - timezone = self._context.get('tz') - except Exception as e: - timezone = self.env.user.tz - - if not timezone: - ks_tzone = os.environ.get('TZ') - if ks_tzone: - timezone = ks_tzone - elif os.path.exists('/etc/timezone'): - ks_tzone = open('/etc/timezone').read() - timezone = ks_tzone[0:-1] - try: - datetime.now(pytz.timezone(timezone)) - except Exception as e: - raise ValidationError(_("Please set the local timezone.")) - - else: - raise ValidationError(_("Please set the local timezone.")) - - 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) - else: - function_name = globals()["ks_date_series_" + series.split("_")[0]] - 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] - return ks_function_name(timezone, type, self) - -def ks_get_date_range_from_td_year(timezone, type,self): - ks_date_data = {} - date = datetime.now(pytz.timezone(timezone)) - year = date.year - start_date = datetime(year, 1, 1) - end_date = date - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data - -def ks_get_date_range_from_td_month(timezone, type,self): - ks_date_data = {} - - date = datetime.now(pytz.timezone(timezone)) - year = date.year - month = date.month - start_date = datetime(year, month, 1) - end_date = date - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data -def ks_get_date_range_from_td_week(timezone, type,self): - ks_date_data = {} - lang = self.env['res.lang']._lang_get(self.env.user.lang) - week_start = lang.week_start - start_Date = rrule.weekday(int(week_start) - 1) - start_date = datetime.today() + relativedelta(weekday=start_Date(-1)) - end_date = datetime.now(pytz.timezone(timezone)) - start_date = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - if type == 'date': - ks_date_data["selected_start_date"] = start_date - end_date = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = end_date - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data -def ks_get_date_range_from_td_quarter(timezone, type,self): - ks_date_data = {} - date = datetime.now(pytz.timezone(timezone)) - year = date.year - quarter = int((date.month - 1) / 3) + 1 - start_date = datetime(year, 3 * quarter - 2, 1) - end_date = date - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data - - -# Last Specific Days Ranges : 7, 30, 90, 365 -def ks_date_series_l(ks_date_selection, timezone, type, self=None): - ks_date_data = {} - date_filter_options = { - 'day': 0, - 'week': 7, - 'month': 30, - 'quarter': 90, - 'year': 365, - 'past': False, - 'future': False - } - end_time = datetime.strptime(datetime.now(pytz.timezone(timezone)).strftime("%Y-%m-%d 23:59:59"), - '%Y-%m-%d %H:%M:%S') - start_time = datetime.strptime((datetime.now(pytz.timezone(timezone)) - timedelta( - days=date_filter_options[ks_date_selection])).strftime("%Y-%m-%d 00:00:00"), '%Y-%m-%d %H:%M:%S') - if type == 'date': - ks_date_data["selected_end_date"] = datetime.strptime(end_time.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_start_date"] = datetime.strptime(start_time.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_time, timezone) - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_time, timezone) - - return ks_date_data - - -# Current Date Ranges : Week, Month, Quarter, year -def ks_date_series_t(ks_date_selection, timezone, type, self=None): - ks_function_name = globals()["ks_get_date_range_from_" + ks_date_selection] - return ks_function_name("current", timezone, type,self) - - -# Previous Date Ranges : Week, Month, Quarter, year -def ks_date_series_ls(ks_date_selection, timezone, type,self=None): - ks_function_name = globals()["ks_get_date_range_from_" + ks_date_selection] - return ks_function_name("previous", timezone, type,self) - - -# Next Date Ranges : Day, Week, Month, Quarter, year -def ks_date_series_n(ks_date_selection, timezone, type,self=None): - ks_function_name = globals()["ks_get_date_range_from_" + ks_date_selection] - return ks_function_name("next", timezone, type, self) - - -def ks_get_date_range_from_day(date_state, timezone, type,self): - ks_date_data = {} - - date = datetime.now(pytz.timezone(timezone)) - - if date_state == "previous": - date = date - timedelta(days=1) - elif date_state == "next": - date = date + timedelta(days=1) - start_date = datetime(date.year, date.month, date.day) - end_date = datetime(date.year, date.month, date.day) + timedelta(days=1, seconds=-1) - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date,timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date,timezone) - return ks_date_data - - -def ks_get_date_range_from_week(date_state, timezone, type,self): - ks_date_data = {} - - # date = datetime.now(pytz.timezone(timezone)) - # ks_week = 0 - lang = self.env['res.lang']._lang_get(self.env.user.lang) - week_start = lang.week_start - start_Date = rrule.weekday(int(week_start) - 1) - start_date = datetime.today() + relativedelta(weekday=start_Date(-1)) - if date_state == "previous": - start_date = datetime.today() - relativedelta(weeks=1, weekday=start_Date(-1)) - elif date_state == "next": - start_date = datetime.today() - relativedelta(weeks=-1, weekday=start_Date(-1)) - - start_date = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - if type == 'date': - ks_date_data["selected_start_date"] = start_date - end_date = start_date + timedelta(days=6, hours=23, minutes=59, seconds=59, milliseconds=59) - ks_date_data["selected_end_date"] = end_date - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - end_date = start_date + timedelta(days=6, hours=23, minutes=59, seconds=59, milliseconds=59) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data - -def ks_get_date_range_from_month(date_state, timezone, type,self): - ks_date_data = {} - - date = datetime.now(pytz.timezone(timezone)) - year = date.year - month = date.month - - if date_state == "previous": - month -= 1 - if month == 0: - month = 12 - year -= 1 - elif date_state == "next": - month += 1 - if month == 13: - month = 1 - year += 1 - - end_year = year - end_month = month - if month == 12: - end_year += 1 - end_month = 1 - else: - end_month += 1 - start_date = datetime(year, month, 1) - end_date = datetime(end_year, end_month, 1) - timedelta(seconds=1) - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data - - -def ks_get_date_range_from_quarter(date_state, timezone, type,self): - ks_date_data = {} - - date = datetime.now(pytz.timezone(timezone)) - year = date.year - quarter = int((date.month - 1) / 3) + 1 - - if date_state == "previous": - quarter -= 1 - if quarter == 0: - quarter = 4 - year -= 1 - elif date_state == "next": - quarter += 1 - if quarter == 5: - quarter = 1 - year += 1 - - start_date = datetime(year, 3 * quarter - 2, 1) - - month = 3 * quarter - remaining = int(month / 12) - end_date = datetime(year + remaining, month % 12 + 1, 1) - timedelta(seconds=1) - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data - - -def ks_get_date_range_from_year(date_state, timezone, type,self): - ks_date_data = {} - - date = datetime.now(pytz.timezone(timezone)) - year = date.year - - if date_state == "previous": - year -= 1 - elif date_state == "next": - year += 1 - start_date = datetime(year, 1, 1) - end_date = datetime(year + 1, 1, 1) - timedelta(seconds=1) - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = datetime.strptime(end_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, timezone) - ks_date_data["selected_end_date"] = ks_convert_into_utc(end_date, timezone) - return ks_date_data - -def ks_get_date_range_from_past(date_state, self_tz, type, self): - ks_date_data = {} - date = datetime.now(pytz.timezone(self_tz)) - if type == 'date': - ks_date_data["selected_end_date"] = datetime.strptime(date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_end_date"] = ks_convert_into_utc(date, self_tz) - ks_date_data["selected_start_date"] = False - return ks_date_data - - -def ks_get_date_range_from_pastwithout(date_state, self_tz, type,self): - ks_date_data = {} - date = datetime.now(pytz.timezone(self_tz)) - hour = date.hour + 1 - date = date - timedelta(hours=hour) - date = datetime.strptime(date.strftime("%Y-%m-%d 23:59:59"), '%Y-%m-%d %H:%M:%S') - ks_date_data["selected_start_date"] = False - if type == 'date': - ks_date_data["selected_end_date"] = datetime.strptime(date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_end_date"] = ks_convert_into_utc(date, self_tz) - return ks_date_data - - -def ks_get_date_range_from_future(date_state, self_tz, type,self): - ks_date_data = {} - date = datetime.now(pytz.timezone(self_tz)) - ks_date_data["selected_end_date"] = False - if type == 'date': - ks_date_data["selected_start_date"] = date.strptime(date.strftime("%Y-%m-%d"), '%Y-%m-%d') - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(date,self_tz) - return ks_date_data - - -def ks_get_date_range_from_futurestarting(date_state, self_tz, type,self): - ks_date_data = {} - date = datetime.now(pytz.timezone(self_tz)) - date = date + timedelta(days=1) - start_date = datetime.strptime(date.strftime("%Y-%m-%d 00:00:00"), '%Y-%m-%d %H:%M:%S') - if type == 'date': - ks_date_data["selected_start_date"] = datetime.strptime(start_date.strftime("%Y-%m-%d"), '%Y-%m-%d') - ks_date_data["selected_end_date"] = False - else: - ks_date_data["selected_start_date"] = ks_convert_into_utc(start_date, self_tz) - ks_date_data["selected_end_date"] = False - return ks_date_data - -def ks_convert_into_utc(datetime, timezone): - ks_tz = timezone and pytz.timezone(timezone) or pytz.UTC - return ks_tz.localize(datetime.replace(tzinfo=None), is_dst=False).astimezone(pytz.UTC).replace(tzinfo=None) - -def ks_convert_into_local(datetime, timezone): - ks_tz = timezone and pytz.timezone(timezone) or pytz.UTC - return pytz.UTC.localize(datetime.replace(tzinfo=None), is_dst=False).astimezone(ks_tz).replace(tzinfo=None) \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/controllers/__init__.py b/addons/ks_dashboard_ninja/controllers/__init__.py deleted file mode 100644 index 798bc50..0000000 --- a/addons/ks_dashboard_ninja/controllers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from . import ks_chart_export -from . import ks_list_export -from . import ks_dashboard_export -from . import ks_domain_fix \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/controllers/ks_chart_export.py b/addons/ks_dashboard_ninja/controllers/ks_chart_export.py deleted file mode 100644 index d72cc4f..0000000 --- a/addons/ks_dashboard_ninja/controllers/ks_chart_export.py +++ /dev/null @@ -1,131 +0,0 @@ - -import re -import datetime -import io -import json -import operator -import logging - -from odoo.addons.web.controllers.export import ExportXlsxWriter -from odoo.tools.translate import _ -from werkzeug.exceptions import InternalServerError -from odoo import http -from odoo.http import content_disposition, request -from odoo.tools.misc import xlwt -from odoo.exceptions import UserError -from odoo.tools import pycompat - -from odoo.exceptions import ValidationError - -_logger = logging.getLogger(__name__) - -class KsChartExport(http.Controller): - - def base(self, data): - params = json.loads(data) - if not params.get('chart_data'): - raise ValidationError("Chart data not present") - 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 = [] - excel_fields = [] - - for dataset in chart_data['datasets']: - dataset['data'].insert(0, dataset['label']) - import_data.append(dataset['data']) - - for i in range(len(columns_headers)): - ks_type_obj = {} - if (len(import_data)): - if isinstance(import_data[0][i],float): - ks_type_obj['type'] = 'float' - else: - ks_type_obj['type'] = '' - excel_fields.append((ks_type_obj)) - - return request.make_response(self.from_data(excel_fields, columns_headers, import_data), - headers=[('Content-Disposition', - content_disposition(self.filename(header))), - ('Content-Type', self.content_type)], - # cookies={'fileToken': token} - ) - -class KsChartExcelExport(KsChartExport, http.Controller): - - # Excel needs raw data to correctly handle numbers and date values - raw_data = True - - @http.route('/ks_dashboard_ninja/export/chart_xls', type='http', auth="user") - def index(self, data): - try: - return self.base(data) - except Exception as exc: - _logger.exception("Exception during request handling.") - payload = json.dumps({ - 'code': 200, - 'message': "Odoo Server Error", - 'data': http.serialize_exception(exc) - }) - raise InternalServerError(payload) from exc - - @property - def content_type(self): - return 'application/vnd.ms-excel' - - def filename(self, base): - return base + '.xlsx' - - def from_data(self, fields, columns_headers, rows): - with ExportXlsxWriter(fields, columns_headers, len(rows)) as xlsx_writer: - for row_index, row in enumerate(rows): - for cell_index, cell_value in enumerate(row): - xlsx_writer.write_cell(row_index + 1, cell_index, cell_value) - - return xlsx_writer.value - - -class KsChartCsvExport(KsChartExport, http.Controller): - - @http.route('/ks_dashboard_ninja/export/chart_csv', type='http', auth="user") - def index(self, data): - try: - return self.base(data) - except Exception as exc: - _logger.exception("Exception during request handling.") - payload = json.dumps({ - 'code': 200, - 'message': "Odoo Server Error", - 'data': http.serialize_exception(exc) - }) - raise InternalServerError(payload) from exc - - @property - def content_type(self): - return 'text/csv;charset=utf8' - - def filename(self, base): - return base + '.csv' - - def from_data(self, fields,columns_headers, rows): - fp = io.BytesIO() - writer = pycompat.csv_writer(fp, quoting=1) - - writer.writerow(columns_headers) - - for data in rows: - row = [] - for d in data: - # Spreadsheet apps tend to detect formulas on leading =, + and - - if isinstance(d, str) and d.startswith(('=', '-', '+')): - d = "'" + d - - row.append(pycompat.to_text(d)) - writer.writerow(row) - - return fp.getvalue() diff --git a/addons/ks_dashboard_ninja/controllers/ks_dashboard_export.py b/addons/ks_dashboard_ninja/controllers/ks_dashboard_export.py deleted file mode 100644 index 7e879ce..0000000 --- a/addons/ks_dashboard_ninja/controllers/ks_dashboard_export.py +++ /dev/null @@ -1,88 +0,0 @@ -import io -import json -import operator -import logging - -# from odoo.addons.web.controllers.main import ExportFormat -from odoo.addons.web.controllers.export import ExportXlsxWriter - -from odoo import http -from odoo.http import request -from odoo.http import content_disposition,request -from werkzeug.exceptions import InternalServerError -_logger = logging.getLogger(__name__) - - -class KsDashboardExport(http.Controller): - - def base(self, data): - params = json.loads(data) - header, dashboard_data = operator.itemgetter('header', 'dashboard_data')(params) - return request.make_response(self.from_data(dashboard_data), - headers=[('Content-Disposition', - content_disposition(self.filename(header))), - ('Content-Type', self.content_type)], - # cookies={'fileToken': token} - ) - - -class KsDashboardJsonExport(KsDashboardExport, http.Controller): - - @http.route('/ks_dashboard_ninja/export/dashboard_json', type='http', auth="user") - def index(self, data): - try: - return self.base(data) - except Exception as exc: - _logger.exception("Exception during request handling.") - payload = json.dumps({ - 'code': 200, - 'message': "Odoo Server Error", - 'data': http.serialize_exception(exc) - }) - raise InternalServerError(payload) from exc - - @property - def content_type(self): - return 'text/csv;charset=utf8' - - def filename(self, base): - return base + '.json' - - def from_data(self, dashboard_data): - fp = io.StringIO() - fp.write(json.dumps(dashboard_data)) - - return fp.getvalue() - -class KsItemJsonExport(KsDashboardExport, http.Controller): - - @http.route('/ks_dashboard_ninja/export/item_json', type='http', auth="user") - def index(self, data): - try: - data = json.loads(data) - item_id = data["item_id"] - data['dashboard_data'] = request.env['ks_dashboard_ninja.board'].ks_export_item(item_id) - data = json.dumps(data) - return self.base(data) - except Exception as exc: - _logger.exception("Exception during request handling.") - payload = json.dumps({ - 'code': 200, - 'message': "Odoo Server Error", - 'data': http.serialize_exception(exc) - }) - raise InternalServerError(payload) from exc - - - @property - def content_type(self): - return 'text/csv;charset=utf8' - - def filename(self, base): - return base + '.json' - - def from_data(self, dashboard_data): - fp = io.StringIO() - fp.write(json.dumps(dashboard_data)) - - return fp.getvalue() diff --git a/addons/ks_dashboard_ninja/controllers/ks_domain_fix.py b/addons/ks_dashboard_ninja/controllers/ks_domain_fix.py deleted file mode 100644 index b4fb31d..0000000 --- a/addons/ks_dashboard_ninja/controllers/ks_domain_fix.py +++ /dev/null @@ -1,21 +0,0 @@ -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/addons/ks_dashboard_ninja/controllers/ks_list_export.py b/addons/ks_dashboard_ninja/controllers/ks_list_export.py deleted file mode 100644 index bb0fbd2..0000000 --- a/addons/ks_dashboard_ninja/controllers/ks_list_export.py +++ /dev/null @@ -1,217 +0,0 @@ -import datetime -import io -import json -import logging -import operator -import os - -import pytz -from dateutil.parser import parse -from odoo.exceptions import ValidationError -from odoo.http import content_disposition, request -from odoo.tools import pycompat -from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT -from werkzeug.exceptions import InternalServerError - -from odoo import http -from odoo.addons.web.controllers.export import ExportXlsxWriter -from ..common_lib.ks_date_filter_selections import ks_get_date, ks_convert_into_local - -_logger = logging.getLogger(__name__) - - -class KsListExport(http.Controller): - - def base(self, data): - params = json.loads(data) - # header,list_data = operator.itemgetter('header','chart_data')(params) - header, list_data, item_id, ks_export_boolean, context, params = operator.itemgetter('header', 'chart_data', - 'ks_item_id', - 'ks_export_boolean', - 'context', 'params')( - params) - list_data = json.loads(list_data) - if not list_data or not list_data.get('label', False): - raise ValidationError("List data not present") - if ks_export_boolean: - item = request.env['ks_dashboard_ninja.item'].browse(int(item_id)) - ks_timezone = item._context.get('tz') or item.env.user.tz - if not ks_timezone: - ks_tzone = os.environ.get('TZ') - if ks_tzone: - ks_timezone = ks_tzone - elif os.path.exists('/etc/timezone'): - ks_tzone = open('/etc/timezone').read() - ks_timezone = ks_tzone[0:-1] - try: - datetime.now(pytz.timezone(ks_timezone)) - except Exception as e: - _logger.info('Please set the local timezone') - - else: - _logger.info('Please set the local timezone') - orderby = item.ks_sort_by_field.id - sort_order = item.ks_sort_by_order - ks_start_date = context.get('ksDateFilterStartDate', False) - ks_end_date = context.get('ksDateFilterEndDate', False) - ksDateFilterSelection = context.get('ksDateFilterSelection', False) - if context.get('allowed_company_ids', False): - item = item.with_context(allowed_company_ids=context.get('allowed_company_ids')) - if item.ks_data_calculation_type == 'query': - query_start_date = item.ks_query_start_date - query_end_date = item.ks_query_end_date - ks_query = str(item.ks_custom_query) - if ks_start_date and ks_end_date: - ks_start_date = parse(ks_start_date) - ks_end_date = parse(ks_end_date) - item = item.with_context(ksDateFilterStartDate=ks_start_date) - item = item.with_context(ksDateFilterEndDate=ks_end_date) - item = item.with_context(ksDateFilterSelection=ksDateFilterSelection) - - if item._context.get('ksDateFilterSelection', False): - ks_date_filter_selection = item._context['ksDateFilterSelection'] - if ks_date_filter_selection == 'l_custom': - item = item.with_context(ksDateFilterStartDate=ks_start_date) - item = item.with_context(ksDateFilterEndDate=ks_end_date) - item = item.with_context(ksIsDefultCustomDateFilter=False) - - else: - ks_date_filter_selection = item.ks_dashboard_ninja_board_id.ks_date_filter_selection - item = item.with_context(ksDateFilterStartDate=item.ks_dashboard_ninja_board_id.ks_dashboard_start_date) - item = item.with_context(ksDateFilterEndDate=item.ks_dashboard_ninja_board_id.ks_dashboard_end_date) - item = item.with_context(ksDateFilterSelection=ks_date_filter_selection) - item = item.with_context(ksIsDefultCustomDateFilter=True) - - if ks_date_filter_selection not in ['l_custom', 'l_none']: - ks_date_data = ks_get_date(ks_date_filter_selection, request, 'datetime') - item = item.with_context(ksDateFilterStartDate=ks_date_data["selected_start_date"]) - item = item.with_context(ksDateFilterEndDate=ks_date_data["selected_end_date"]) - - item_domain = params.get('ks_domain_1', []) - ks_chart_domain = item.ks_convert_into_proper_domain(item.ks_domain, item,item_domain) - # list_data = item.ks_fetch_list_view_data(item,ks_chart_domain, ks_export_all= - if list_data['type'] == 'ungrouped': - list_data = item.ks_fetch_list_view_data(item, ks_chart_domain, ks_export_all=True) - elif list_data['type'] == 'grouped': - list_data = item.get_list_view_record(orderby, sort_order, ks_chart_domain, ks_export_all=True) - elif item.ks_data_calculation_type == 'query': - if ks_start_date or ks_end_date: - query_start_date = ks_start_date - query_end_date = ks_end_date - ks_query_result = item.ks_get_list_query_result(ks_query, query_start_date, query_end_date, ks_offset=0, - ks_export_all=True) - list_data = item.ks_format_query_result(ks_query_result) - - # chart_data['labels'].insert(0,'Measure') - columns_headers = list_data['label'] - import_data = [] - excel_fields = [] - for dataset in list_data['data_rows']: - if not list_data['type'] == 'grouped': - for count, index in enumerate(dataset['ks_column_type']): - if index == 'datetime': - ks_converted_date = False - date_string = dataset['data'][count] - if dataset['data'][count]: - ks_converted_date = ks_convert_into_local(datetime.datetime.strptime(date_string, '%m/%d/%y %H:%M:%S'),ks_timezone) - dataset['data'][count] = ks_converted_date - for ks_count, val in enumerate(dataset['data']): - if isinstance(val, (float, int)): - if val >= 0: - try: - ks_precision = item.sudo().env.ref('ks_dashboard_ninja.ks_dashboard_ninja_precision').digits - except Exception as e: - ks_precision = 2 - dataset['data'][ks_count] = item.env['ir.qweb.field.float'].sudo().value_to_html(val, - {'precision': ks_precision}) - import_data.append(dataset['data']) - for i in range(len(columns_headers)): - ks_type_obj = {} - if (len(import_data)): - if isinstance(import_data[0][i], float): - ks_type_obj['type'] = 'float' - else: - ks_type_obj['type'] = '' - excel_fields.append((ks_type_obj)) - - return request.make_response(self.from_data(excel_fields, columns_headers, import_data), - headers=[('Content-Disposition', - content_disposition(self.filename(header))), - ('Content-Type', self.content_type)], - # cookies={'fileToken': token} - ) - - -class KsListExcelExport(KsListExport, http.Controller): - - # Excel needs raw data to correctly handle numbers and date values - raw_data = True - - @http.route('/ks_dashboard_ninja/export/list_xls', type='http', auth="user") - def index(self, data): - try: - return self.base(data) - except Exception as exc: - _logger.exception("Exception during request handling.") - payload = json.dumps({ - 'code': 200, - 'message': "Odoo Server Error", - 'data': http.serialize_exception(exc) - }) - raise InternalServerError(payload) from exc - - @property - def content_type(self): - return 'application/vnd.ms-excel' - - def filename(self, base): - return base + '.xlsx' - - def from_data(self, fields, columns_headers, rows): - with ExportXlsxWriter(fields, columns_headers, len(rows)) as xlsx_writer: - for row_index, row in enumerate(rows): - for cell_index, cell_value in enumerate(row): - xlsx_writer.write_cell(row_index + 1, cell_index, cell_value) - - return xlsx_writer.value - - -class KsListCsvExport(KsListExport, http.Controller): - - @http.route('/ks_dashboard_ninja/export/list_csv', type='http', auth="user") - def index(self, data): - try: - return self.base(data) - except Exception as exc: - _logger.exception("Exception during request handling.") - payload = json.dumps({ - 'code': 200, - 'message': "Odoo Server Error", - 'data': http.serialize_exception(exc) - }) - raise InternalServerError(payload) from exc - - @property - def content_type(self): - return 'text/csv;charset=utf8' - - def filename(self, base): - return base + '.csv' - - def from_data(self, fields, column_headers,rows): - fp = io.BytesIO() - writer = pycompat.csv_writer(fp, quoting=1) - - writer.writerow(column_headers) - - for data in rows: - row = [] - for d in data: - # Spreadsheet apps tend to detect formulas on leading =, + and - - if isinstance(d, str) and d.startswith(('=', '-', '+')): - d = "'" + d - - row.append(pycompat.to_text(d)) - writer.writerow(row) - - return fp.getvalue() diff --git a/addons/ks_dashboard_ninja/data/dn_data.xml b/addons/ks_dashboard_ninja/data/dn_data.xml deleted file mode 100644 index da76cfd..0000000 --- a/addons/ks_dashboard_ninja/data/dn_data.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - ks_dashboard_ninja.url - https://dn16ai.kappso.com - - - \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/data/ks_default_data.xml b/addons/ks_dashboard_ninja/data/ks_default_data.xml deleted file mode 100644 index 9858ccf..0000000 --- a/addons/ks_dashboard_ninja/data/ks_default_data.xml +++ /dev/null @@ -1,614 +0,0 @@ - - - - - - - Blank - 0 - - - - Template 1 - [ - {"item_id":"ks_dashboard_ninja.ks_default_item_1", "data": {"x": 0, "y": 10, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_2", "data": {"x": 0, "y": 8, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_3", "data": {"x": 3, "y": 0, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_4", "data": {"x": 0, "y": 2, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_5", "data": {"x": 6, "y": 12, "w": 6, "h": 6}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_6", "data": {"x": 0, "y": 28, "w": 12, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_7", "data": {"x": 0, "y": 43, "w": 5, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_8", "data": {"x": 6, "y": 6, "w": 6, "h": 6}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_9", "data": {"x": 5, "y": 36, "w": 7, "h": 7}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_10", "data": {"x": 4, "y": 23, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_11", "data": {"x": 6, "y": 18, "w": 6, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_12", "data": {"x": 0, "y": 6, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_13", "data": {"x": 3, "y": 8, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_15", "data": {"x": 0, "y": 18, "w": 6, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_16", "data": {"x": 0, "y": 0, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_17", "data": {"x": 3, "y": 6, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_18", "data": {"x": 3, "y": 4, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_19", "data": {"x": 3, "y": 10, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_20", "data": {"x": 5, "y": 43, "w": 7, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_21", "data": {"x": 0, "y": 12, "w": 6, "h": - 6}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_22", "data": {"x": 0, "y": 36, "w": 5, "h": - 7}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_23", "data": {"x": 0, "y": 32, "w": 12, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_24", "data": {"x": 8, "y": 23, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_25", "data": {"x": 0, "y": 23, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_26", "data": {"x": 0, "y": 4, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_27", "data": {"x": 3, "y": 3, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_28", "data": {"x": 6, "y": 0, "w": 6, "h": - 6}} - ] - - 7 - - - - Template 2 - [ - {"item_id":"ks_dashboard_ninja.ks_default_item_1", "data": {"x": 0, "y": 0, "w": 2, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_2", "data": {"x": 4, "y": 0, "w": 2, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_3", "data": {"x": 2, "y": 0, "w": 2, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_4", "data": {"x": 8, "y": 0, "w": 2, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_5", "data": {"x": 4, "y": 18, "w": 8, "h": 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_6", "data": {"x": 8, "y": 27, "w": 4, "h": - 6}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_7", "data": {"x": 0, "y": 18, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_8", "data": {"x": 4, "y": 27, "w": 4, "h": - 6}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_9", "data": {"x": 4, "y": 13, "w": 8, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_10", "data": {"x": 0, "y": 23, "w": 4, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_11", "data": {"x": 0, "y": 4, "w": 4, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_12", "data": {"x": 6, "y": 0, "w": 2, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_13", "data": {"x": 10, "y": 2, "w": 2, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_15", "data": {"x":0, "y": 33, "w": 6, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_16", "data": {"x": 2, "y": 2, "w": 2, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_17", "data": {"x": 8, "y": 2, "w": 2, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_18", "data": {"x": 6, "y": 2, "w": 2, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_19", "data": {"x": 0, "y": 2, "w": 2, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_20", "data": {"x": 4, "y": 8, "w": 8, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_21", "data": {"x": 0, "y": 13, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_22", "data": {"x": 4, "y": 23, "w": 8, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_23", "data": {"x": 6, "y": 33, "w": 6, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_24", "data": {"x": 4, "y": 4, "w": 8, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_25", "data": {"x": 0, "y": 8, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_26", "data": {"x": 4, "y": 2, "w": 2, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_27", "data": {"x": 10, "y": 2, "w": 2, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_28", "data": {"x": 0, "y": 27, "w": 4, "h": - 6}} - ] - - 7 - - - - Template 3 - [ - {"item_id":"ks_dashboard_ninja.ks_default_item_1", "data": {"x": 0, "y": 0, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_2", "data": {"x": 6, "y": 0, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_3", "data": {"x": 3, "y": 0, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_4", "data": {"x": 0, "y": 2, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_5", "data": {"x": 7, "y": 2, "w": 5, "h": 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_6", "data": {"x": 0, "y": 28, "w": 12, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_7", "data": {"x": 4, "y": 14, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_8", "data": {"x": 0, "y": 33, "w": 3, "h": 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_9", "data": {"x": 8, "y": 23, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_10", "data": {"x": 8, "y": 14, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_11", "data": {"x": 0, "y": 23, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_12", "data": {"x": 9, "y": 0, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_13", "data": {"x": 3, "y": 2, "w": 4, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_15", "data": {"x":0, "y": 19, "w": 12, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_16", "data": {"x": 0, "y": 8, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_17", "data": {"x": 3, "y": 4, "w": 4, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_18", "data": {"x": 0, "y": 12, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_19", "data": {"x": 0, "y": 4, "w": 3, "h": 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_20", "data": {"x": 3, "y": 6, "w": 9, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_21", "data": {"x": 0, "y": 14, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_22", "data": {"x": 6, "y": 33, "w": 6, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_23", "data": {"x": 0, "y": 19, "w": 12, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_24", "data": {"x": 3, "y": 10, "w": 9, "h": - 4}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_25", "data": {"x": 4, "y": 23, "w": 4, "h": - 5}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_26", "data": {"x": 0, "y": 8, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_27", "data": {"x": 0, "y": 6, "w": 3, "h": - 2}}, - {"item_id":"ks_dashboard_ninja.ks_default_item_28", "data": {"x": 3, "y": 33, "w": 3, "h": - 5}} - ] - - 7 - - - - - - - Tile (layout 1) - ks_tile - count - - [["id",">",150]] - bar-chart - blue - #FFE2E5,0.99 - #000000,0.99 - #000000,0.99 - layout1 - - - - - - Tile (layout 3) - ks_tile - count - - users - red - #FFF4DE,0.99 - #000000,0.99 - #000000,0.99 - layout3 - - - - - - Tile (layout 2) - ks_tile - count - - [["id","<",50]] - money - green - #DCFCE7,0.99 - #000000,0.99 - #000000,0.99 - layout2 - - - - - - Tile (layout 5) - ks_tile - count - - [["id","<",100]] - paper-plane - yellow - #F3E8FF,0.99 - #000000,0.99 - #000000,0.99 - layout5 - - - - - - Bar Chart - sum - relational_type - - - - - [["id","<",40]] - dark - ks_bar_chart - - - - - - - Line Chart - sum - relational_type - - - - - [["id","<",10]] - dark - ks_line_chart - - - - - - Pie Chart - sum - relational_type - - - - [["id","<",10]] - ks_pie_chart - - - - - list view (Un-Grouped) - sum - relational_type - - grouped - - - [["id","<",10]] - ks_list_view - - - - Horizontal Bar - sum - relational_type - - - - [["id","<",10]] - material - ks_horizontalBar_chart - - - - Polar Area - sum - relational_type - - - - [["id","<",10]] - moonrise - ks_polarArea_chart - - - - Doughnut chart - sum - relational_type - - - - [["id","<",10]] - moonrise - 100 - 1 - monetary - ks_doughnut_chart - - - - Tile (layout 4) - ks_tile - count - - [["id","<",50]] - shopping-cart - red - #FFE2E5,0.99 - #000000,0.99 - #000000,0.99 - layout4 - - - - Tile (layout 6) - ks_tile - count - - [["id","<",100]] - car - red - #FFF4DE,0.53 - #000000,0.70 - #000000,0.99 - layout6 - - - - Pie Chart - sum - relational_type - - - - [["id","<",10]] - dark - ks_pie_chart - - - - Area Chart - sum - relational_type - - - - default - ks_area_chart - - - - - Kpi Ratio - ks_kpi - count - count - - - Ratio - [["id","<",100]] - user - blue - #DCFCE7,0.99 - #000000,0.99 - #000000,0.99 - - - - Kpi ( Percentage) - ks_kpi - count - count - - - [["id","<",100]] - Percentage - paper-plane - red - #F3E8FF,0.99 - #000000,0.99 - #000000,0.99 - - - - Kpi ( Number) - ks_kpi - count - count - - - Number - 1 - [["id","<",100]] - Sum - money - green - #F3E8FF,0.63 - #000000,0.99 - #000000,0.99 - - - - Kpi (sum) - ks_kpi - count - count - - - Sum - [["id","<",100]] - bar-chart - yellow - #FFF4DE,0.99 - #000000,0.99 - #000000,0.99 - - - - Bar Chart With Data Values - sum - relational_type - - - - [["id","<",40]] - default - ks_bar_chart - 1 - monetary - - - - - Semi Circle Pie Chart - sum - relational_type - - - - 1 - material - 10 - 1 - monetary - ks_pie_chart - - - - Horizontal Bar(sub-group) - sum - relational_type - - - - - default - [["id","<",10]] - 1 - monetary - ks_horizontalBar_chart - - - - Area Chart with data values - sum - relational_type - - - - material - 25 - 1 - monetary - ks_area_chart - - - - Line Chart with values - sum - relational_type - - - - moonrise - 10 - 1 - monetary - ks_line_chart - - - - Doughnut semi circle - sum - relational_type - - - - default - 1 - 25 - 1 - monetary - ks_doughnut_chart - - - - Kpi 26(Average) - ks_kpi - - - indian - average - average - - - Number - 1 - [["id","<",100]] - Sum - money - blue - #DCFCE7,0.99 - #000000,0.99 - #000000,0.99 - - - - Kpi (previous) - ks_kpi - count - - [["id","<",100]] - 1 - t_week - money - green - #FFE2E5,0.59 - #000000,0.99 - #000000,0.99 - - - - list view (grouped) - sum - relational_type - - - ungrouped - - - [["id","<",10]] - ks_list_view - - - - - ks_bar_chart - - - - - ks_pie_chart - - - - - - - - My Dashboard - Locked - My Dashboard - 1 - - - - - - Dashboard Ninja Decimal Precision - - - - \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/data/ks_mail_cron.xml b/addons/ks_dashboard_ninja/data/ks_mail_cron.xml deleted file mode 100644 index c19bbc2..0000000 --- a/addons/ks_dashboard_ninja/data/ks_mail_cron.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - Kpi mail cron - 1 - days - - model.check_target() - code - - \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/data/sequence.xml b/addons/ks_dashboard_ninja/data/sequence.xml deleted file mode 100644 index 26403ed..0000000 --- a/addons/ks_dashboard_ninja/data/sequence.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Dashboard Seq - ks_dashboard_ninja.item - 2 - - - - \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/demo/ks_dashboard_ninja_demo.xml b/addons/ks_dashboard_ninja/demo/ks_dashboard_ninja_demo.xml deleted file mode 100644 index 29c1f44..0000000 --- a/addons/ks_dashboard_ninja/demo/ks_dashboard_ninja_demo.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - Template1 Dashboard - Template1 - - - 1 - - - - - Template2 Dashboard - Template2 - - - 1 - - - - - Template3 Dashboard - Template3 - - - 1 - - - - diff --git a/addons/ks_dashboard_ninja/i18n/en_US.po b/addons/ks_dashboard_ninja/i18n/en_US.po deleted file mode 100644 index 9b3be0e..0000000 --- a/addons/ks_dashboard_ninja/i18n/en_US.po +++ /dev/null @@ -1,3070 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * ks_dashboard_ninja -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-05-26 14:51+0000\n" -"PO-Revision-Date: 2021-05-26 14:51+0000\n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_dashboard_board_id -msgid "" -"\n" -" Items Configuration and their position in the dashboard will be copied from the selected dashboard \n" -" and will be saved as template.\n" -" " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_previous_period -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 "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_relation_groupby -msgid " Define the x-axis of the graph. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_year_period -msgid " Display the record for the same Date field for the last year. " -msgstr "" - -#. 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 -#: 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 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_date_filter_selection__ls_pastwithout_now -msgid " Past Excluding Today" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_compare_period -msgid "" -" Provide the number of Date Filter Selection you want to include while " -"displaying the record." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_data_limit -msgid " Records to be displayed on the graph" -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 -msgid " Select the background color with transparency. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_fields -msgid " Select the fields you want to display in the list. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_layout -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 -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 -msgid " Select the view to compare target with data." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_relation_sub_groupby -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 "" - -#. 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 "" - -#. 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 "" - -#. 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 "" - -#. 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 "" - -#. 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 "" - -#. 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 "" - -#. 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 "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#, python-format -msgid "" -"

\n" -" You can find all items related to Dashboard Here.

\n" -" " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__ks_action -msgid "Action" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_item_action_field -msgid "Action Group By" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_action_lines -msgid "Action Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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__ks_actions -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Actions" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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 -msgid "Active" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__ks_active -msgid "Active Description" -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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Add Item" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Add a Line" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -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 -#, python-format -msgid "Add a condition" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_form -msgid "Add a filter" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_form -msgid "Add a separator" -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 button" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Advance Configuration" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "" -"All Target Lines Changes Will be reflected on Chart after saving the record " -"and pagination will be ignore ." -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_board__ks_date_filter_selection__l_none -#, python-format -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 "" - -#. 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_dn_global_filter.xml:0 -#, python-format -msgid "Apply" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#, python-format -msgid "Archive" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#, python-format -msgid "Are you sure that you want to archive all the selected records?" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js:0 -#, python-format -msgid "Are you sure you want to remove this task?" -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 -msgid "Area Chart" -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 -msgid "Ascending" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -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 -msgid "Average" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_background_color -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 -msgid "Bar Chart" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_base -msgid "Base" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Below action will be performed at the end of the Drill Down Action" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_action -msgid "Cancel" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format -msgid "" -"Cannot create target lines when Group By Date field is set to have " -"aggregation in Minute and Hour case." -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format -msgid "" -"Cannot set aggregation having Date time (Hour, Minute) when target lines per" -" date are being used. To proceed this, first delete target lines" -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 "" -"Changing Layout midway will set the default icon colour and font colour for " -"selected layout." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_item_color -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Chart Color Palette" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_data -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 "" - -#. 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 "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_icon_select -msgid "Choose the Icon option. " -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_item_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Clear" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_is_client_action -msgid "Client Action" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_client_action -msgid "Client Item Action" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js: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 -msgid "Close" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_format__colombian -msgid "Colombian Peso Format" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Color Palette" -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 "Coming Soon in Future :)" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_company_id -msgid "Company" -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 "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_data_count_type__count -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_record_count_type_2__count -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_record_count_type__count -msgid "Count" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view -msgid "Count..." -msgstr "" - -#. module: ks_dashboard_ninja -#: 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_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_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 -msgid "Created by" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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_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_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 -msgid "Created on" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_cumulative -msgid "Cumulative As Line" -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 "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#: 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." -msgstr "" - -#. 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_unit_selection__custom -msgid "Custom" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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 -#: 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 -#, python-format -msgid "Custom Filter" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_form -msgid "Custom Filters" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_calculation_type__query -msgid "Custom Query" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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_item_templates.xml:0 -#: 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_item_templates.xml:0 -#: 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_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_ninja_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_ninja_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_ninja_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_ninja_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_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#, python-format -msgid "Customize Item" -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 -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_dashboard_board_id -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_ninja_board_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 -msgid "Dashboard" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_custom_filters_ids -msgid "Dashboard Custom Filters" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_defined_filters -msgid "Dashboard Defined Filter" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_action -msgid "Dashboard Item Action" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_date_groupby -msgid "Dashboard Item Chart Group By Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_date_sub_groupby -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_ninja_item__ks_dashboard_item_type -msgid "Dashboard Item Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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 -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__ks_dashboard_item_ids -#, python-format -msgid "Dashboard Items" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.child_board_tree -msgid "Dashboard Layout" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.ui.menu,name:ks_dashboard_ninja.dashboard_layout_menu -msgid "Dashboard Layouts" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.actions.act_window,name:ks_dashboard_ninja.board_form_tree_action_window -msgid "Dashboard Manager" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__name -msgid "Dashboard Name" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_board -msgid "Dashboard Ninja" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_child_board -msgid "Dashboard Ninja Child Board" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_board_custom_filters -msgid "Dashboard Ninja Custom Filters" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_board_defined_filters -msgid "Dashboard Ninja Defined Filters" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_ninja_dashboard_item_action -msgid "Dashboard Ninja Item Actions" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_item_action -msgid "Dashboard Ninja Items Action Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_item_goal -msgid "Dashboard Ninja Items Goal Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.module.category,name:ks_dashboard_ninja.ks_dashboard_ninja_security_groups -msgid "Dashboard Ninja Rights" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_board_template -msgid "Dashboard Ninja Template" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_dashboard_ninja_item -msgid "Dashboard Ninja items" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_defined_filters_ids -msgid "Dashboard Predefined Filters" -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_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_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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.actions.act_window,name:ks_dashboard_ninja.layout_tree_action_window -msgid "Dashboard layout" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.ui.menu,name:ks_dashboard_ninja.dashboard_menu -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_form -msgid "Dashboards" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Data" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Data #2" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Data Calculation" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_calculation_type -msgid "Data Calculation Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_kpi_type__layout_2 -msgid "Data Comparison" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_measure_field_2 -msgid "Data Points displayed with a line in the graph. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_data_count_type -msgid "Data Type" -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 -msgid "Data points to be selected." -msgstr "" - -#. module: ks_dashboard_ninja -#: 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 -msgid "" -"Data source to fetch and read the data for the creation of dashboard items. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_goal__ks_goal_date -msgid "Date" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Date Filter" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_field -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Date Filter Field" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_selection -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Date Filter Selection" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__day -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_sub_groupby__day -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_item_action_date_groupby__day -msgid "Day" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_item_color__default -msgid "Default" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#, python-format -msgid "Default Dashboard can't be deleted." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_date_filter_selection -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 -msgid "Default Query" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_set_interval -msgid "Default Update Interval" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_extension -msgid "Define conditions for filter to write manually" -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 -msgid "Define conditions for filter. " -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#: 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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 -#, python-format -msgid "Delete" -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 -msgid "Descending" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__ks_description -msgid "Description" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Deviation Field" -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_ninja_templates.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_quick_edit_view.xml:0 -#, python-format -msgid "Discard" -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_ninja_templates.xml:0 -#, python-format -msgid "Discard Changes" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Display" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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_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_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 -msgid "Display Name" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__display_type -msgid "Display Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_unit -msgid "Display the unit of the data." -msgstr "" - -#. 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 -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Domain" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_extension -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Domain Extension" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__ks_domain_field_id -msgid "Domain Field" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__ks_domain_temp -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_temp -msgid "Domain Substitute" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_filters.py:0 -#, 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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Drill Up" -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_ninja_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_ninja_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_ninja_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_ninja_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.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 -#, python-format -msgid "Duplicate" -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_ninja_templates.xml:0 -#: 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 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_to_do_dashboard.js:0 -#, python-format -msgid "Edit Task" -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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_end_date -#: 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 "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_format__global -msgid "English Format" -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 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_data_formatting__exact -msgid "Exact" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_format__exact -msgid "Exact Value" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_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_ninja_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_ninja_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_ninja_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml: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 -msgid "Export All Records" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Export Chart" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js: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_ninja_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_ninja_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_ninja_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_ninja_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_ninja_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_ninja_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_ninja_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_ninja_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_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.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 -#, 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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Export to CSV" -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_dashboard_pro.xml:0 -#, python-format -msgid "Export to Excel" -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 "Fields Required : Name, Model, Icon (Default or Custom Upload), Layout" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_fields -#: 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 "Fields to show in list" -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 -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -#, python-format -msgid "Filter" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_custom_filters__name -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__name -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 -#, python-format -msgid "Font Awesome 4.7.0" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_font_color -msgid "Font Color" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_data_formatting -msgid "Format" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Future Starting Now" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Future Starting Tomorrow" -msgstr "" - -#. 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." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_data_formatting__global -msgid "Global" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Goal Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_graph_preview -msgid "Graph Preview" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_group_access -msgid "Group Access" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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 -msgid "Group By" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_item_action_date_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 -msgid "Group By Date" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format -msgid "Groupby Field aggregation" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format -msgid "Groupby field: {} cannot be aggregated by {}" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_list_view_type__grouped -msgid "Grouped" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Groups/Dimensions" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__ks_to_do_header -msgid "Header" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_header_bg_color -msgid "Header Background Color" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_hide_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: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: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 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_item_action_date_groupby__hour -msgid "Hour" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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_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_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 -msgid "ID" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_default_icon -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Icon" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_default_icon_color -msgid "Icon Color" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_icon_select -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 -#, python-format -msgid "Import Dashboard" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, 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 -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Include Period" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board__ks_data_formatting__indian -msgid "Indian" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_data_format__indian -msgid "Indian Format" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Invalid Date" -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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Item Action" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_gridstack_config -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_child_board__ks_gridstack_config -msgid "Item Configurations" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Item Duplicated" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Item Moved" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_chart_type -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 -#, python-format -msgid "KPI" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_kpi_data -msgid "KPI Data" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_extension_2 -msgid "KPI Domain Extension" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_compare_period_2 -msgid "KPI Include Period" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_count_2 -msgid "KPI Record Count" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_year_period_2 -msgid "KPI Same Period Previous Years" -msgstr "" - -#. 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 "" - -#. 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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_field_2 -msgid "Kpi Date Filter Field" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_selection_2 -msgid "Kpi Date Filter Selection" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_2 -msgid "Kpi Domain" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_domain_2_temp -msgid "Kpi Domain Substitute" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_item_end_date_2 -msgid "Kpi End Date" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_kpi_type -msgid "Kpi Layout" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_model_id_2 -msgid "Kpi Model" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_model_name_2 -msgid "Kpi Model Name" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_kpi_preview -msgid "Kpi Preview" -msgstr "" - -#. 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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_count_type_2 -msgid "Kpi Record Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_item_start_date_2 -msgid "Kpi Start Date" -msgstr "" - -#. 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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_sub_groupby_type -msgid "Ks Chart Sub Groupby Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_child_dashboard_ids -msgid "Ks Child Dashboard" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_client_action_id -msgid "Ks Dashboard Client Action" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_menu_id -msgid "Ks Dashboard Menu" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_state -msgid "Ks Dashboard State" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dn_header_lines -msgid "Ks Dn Header Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__ks_dn_item_id -msgid "Ks Dn Item" -msgstr "" - -#. 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_isDateFilterApplied -msgid "Ks Isdatefilterapplied" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_item_action_field_type -msgid "Ks Item Action Field Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_item_count -msgid "Ks Item Count" -msgstr "" - -#. 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 "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_headers__ks_to_do_description_lines -msgid "Ks To Do Description Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_to_do_description__ks_to_do_header_id -msgid "Ks To Do Header" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Last 30 days" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Last 365 days" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -msgid "Last 7 days" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Last 90 days" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -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 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Last Month" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Last Quarter" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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_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_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 "" - -#. module: ks_dashboard_ninja -#: 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_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_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 -msgid "Last Updated on" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Last Week" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Last Year" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_layout -msgid "Layout" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout1 -msgid "Layout 1" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout2 -msgid "Layout 2" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout3 -msgid "Layout 3" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout4 -msgid "Layout 4" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_layout__layout5 -msgid "Layout 5" -msgstr "" - -#. 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 "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Layout Coming Soon" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view -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 -msgid "Line Chart" -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 -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view -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 "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_data -msgid "List View Data in JSon" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_group_fields -msgid "List View Grouped Fields" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_preview -msgid "List View Preview" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_type -msgid "List View Type" -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 "" - -#. 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 "" - -#. 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 "Measures" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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 -msgid "Menu Name" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_menu_sequence -msgid "Menu Sequence" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__minute -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_sub_groupby__minute -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_item_action_date_groupby__minute -msgid "Minute" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Model" -msgstr "" - -#. 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 -msgid "Model Name" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view -msgid "Model..." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_unit_selection__monetary -msgid "Monetary" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_groupby__month -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_chart_date_sub_groupby__month -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_item_action_date_groupby__month -msgid "Month" -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 -msgid "Month-Year" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.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_ninja_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_ninja_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_ninja_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_ninja_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.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 -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_ninja_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_ninja_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_ninja_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_ninja_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#, python-format -msgid "Move/Duplicate" -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_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 -msgid "Name" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_company_id -msgid "" -"Name of the company for which analytics will be displayed in the dashboard. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view -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 "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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 -msgid "Next" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Next Day" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Next Month" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Next Quarter" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Next Week" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Next Year" -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_dashboard_pro.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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#, python-format -msgid "No Tasks Available" -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_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 -#, 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 -#, 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 -msgid "Number" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_format -msgid "Number System" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_pagination_limit -msgid "Pagination Limit" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format -msgid "Pagination limit value cannot be Negative or Zero" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Past Excluding Today" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -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 -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 -msgid "Pie Chart" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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 "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format -msgid "Please chose any Data Type!" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#: code:addons/ks_dashboard_ninja/lib/ks_date_filter_selections.py:0 -#, 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 -msgid "" -"Please use Font Awesome 4.7.0 icons only. E.g. 'fa-bell' or 'bell'.\n" -" For more information visit" -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 -msgid "Pre Defined Filters" -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 -msgid "Predefined" -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 -msgid "Preview" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Previous" -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_ninja_templates.xml:0 -#: 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 -msgid "Progress Bar" -msgstr "" - -#. 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 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_item_action_date_groupby__quarter -msgid "Quarter" -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_ninja_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_ninja_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_ninja_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_ninja_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_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_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 -msgid "Ratio" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_count -msgid "Record Count" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_field -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Record Field" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_quick_edit_form_view -msgid "Record Field..." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_data_limit -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_record_limit -msgid "Record Limit" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_data_limit_visibility -msgid "Record Limit Data Visibility" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_count_type -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Record Type" -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.item_quick_edit_form_view -msgid "Record Value" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_actions -msgid "Redirects you to the selected view. " -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 -#: 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_item_templates.xml:0 -#: 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_item_templates.xml:0 -#: 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_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_ninja_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_ninja_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_ninja_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_ninja_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_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.xml:0 -#, python-format -msgid "Remove Item" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_year_period -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Same Period Previous Years" -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_quick_edit_view.xml:0 -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.ks_dashboard_ninja_action -#, python-format -msgid "Save" -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_ninja_templates.xml:0 -#, python-format -msgid "Save Changes" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Save Changes as a New Layout" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Save as Image" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "Save as New Layout" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_pro.xml:0 -#, python-format -msgid "Save as PDF" -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 -#, python-format -msgid "Search fa-icon.." -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 "Search through site content" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_board_defined_filters__display_type__line_section -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -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 -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_ninja_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_ninja_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_ninja_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_ninja_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_dashboard_pro.xml:0 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_to_do_template.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 -msgid "Select Dashboard" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_ninja_dashboard_item_action__ks_dashboard_ninja_ids -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 "" - -#. 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 Icons" -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 -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_selection -msgid "Select interval of the records to be displayed. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_item_theme -msgid "Select the color theme for the display. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_view_type -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 -msgid "Select the desired sorting preference. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_item_color -msgid "Select the display preference. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_date_filter_field -msgid "Select the field for which Date Filter should be applicable." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_font_color -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 -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 -msgid "Select the required type of dashboard to display. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_chart_relation_sub_groupby -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 -msgid "Select the type of calculation you want to perform on the data." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_unit_selection -msgid "Select the unit to be assigned to the value. " -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 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Selected item is duplicated to ." -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Selected item is moved to ." -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_domain_fix.js:0 -#, python-format -msgid "Selected records" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_semi_circle_chart -msgid "Semi Circle Chart" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_defined_filters -msgid "Separator Name (eg. Order States, Deadlines)" -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 -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 "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Set Update Interval" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_unit -msgid "Show Custom Unit" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_show_data_value -msgid "Show Data Value" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:res.groups,name:ks_dashboard_ninja.ks_dashboard_ninja_group_manager -msgid "Show Full Dashboard Features" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_hide_legend -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 "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_show_records -msgid "Show Records" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_goal_bar_line -msgid "Show Target As Line" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_top_menu_id -msgid "Show Under Menu" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_standard_goal_value -msgid "Show the set target" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_goal_enable -msgid "Show the set target." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_menu_sequence -msgid "" -"Smallest sequence give high priority and Highest sequence give low priority" -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 "" - -#. module: ks_dashboard_ninja -#: 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" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_sort_by_field -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_sort_by_field -msgid "Sort By Field" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_sort_by_order -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item_action__ks_sort_by_order -msgid "Sort Order" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_bar_chart_stacked -msgid "Stack the columns of the same record. " -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_bar_chart_stacked -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Stacked Bar Chart" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_standard_goal_value -msgid "Standard Target" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board__ks_dashboard_start_date -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_item_start_date -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Start Date" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#, python-format -msgid "Start date must be less than end date" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.js:0 -#, python-format -msgid "Start date should be less than end date" -msgstr "" - -#. 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 -#: 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 -#: 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_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 -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Target" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_goal_lines -msgid "Target Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Task Lines" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.item_form_view -msgid "Tasks" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_board_defined_filters__display_type -msgid "Technical field for UX purpose." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_template_type -msgid "Template Format" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_board_template__ks_dashboard_item_ids -msgid "Template Type" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__name -msgid "The item will be represented by this unique name." -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_dashboard_item_theme -msgid "Theme" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_client_action -msgid "This Action will be Performed at the end of Drill Down Action" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "This Month" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "This Quarter" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "This Week" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "This Year" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_show_records -msgid "" -"This field Enable the click on \n" -" Dashboard Items to view the Odoo \n" -" default view of records" -msgstr "" - -#. module: ks_dashboard_ninja -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py:0 -#: 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 -msgid "Tile" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_data_format -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 -msgid "To Do Data in JSon" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_to_do_preview -msgid "To Do Preview" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dashboard_ninja_templates.xml:0 -#, python-format -msgid "To add dashboard item, use" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,help:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_record_data_limit_visibility -msgid "To enable the record data limit field" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_dashboard_ninja.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 -#, python-format -msgid "Today" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_button_color -msgid "Top Button Color" -msgstr "" - -#. module: ks_dashboard_ninja -#: 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 -msgid "" -"Type of record how record will show as count,sum and average of the record" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item__ks_list_view_type__ungrouped -msgid "Un-Grouped" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#: code:addons/ks_dashboard_ninja/static/src/js/ks_import_dashboard.js:0 -#, python-format -msgid "Unarchive" -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 "" - -#. 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 -#, 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 -msgid "Value" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_target_view -msgid "View" -msgstr "" - -#. module: ks_dashboard_ninja -#: model_terms:ir.ui.view,arch_db:ks_dashboard_ninja.board_tree -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 -#: model:ir.model.fields.selection,name:ks_dashboard_ninja.selection__ks_dashboard_ninja_item_action__ks_item_action_date_groupby__week -msgid "Week" -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 "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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 -#: code:addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py:0 -#, python-format -msgid "if target lines is selected then cannot be set pagination value" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model.fields,field_description:ks_dashboard_ninja.field_ks_dashboard_ninja_item__ks_list_target_deviation_field -msgid "list_field_id" -msgstr "" - -#. module: ks_dashboard_ninja -#. openerp-web -#: 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 -#: code:addons/ks_dashboard_ninja/static/src/xml/ks_dn_global_filter.xml:0 -#, python-format -msgid "or" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_to_do_description -msgid "to do description" -msgstr "" - -#. module: ks_dashboard_ninja -#: model:ir.model,name:ks_dashboard_ninja.model_ks_to_do_headers -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_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_ninja_templates.xml:0 -#, python-format -msgid "vs Prev" -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_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_ninja_templates.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 -msgid "" -"when click on boolean button, all the records will be downloaded which are " -"present in entire list" -msgstr "" diff --git a/addons/ks_dashboard_ninja/models/Kpi_mail.py b/addons/ks_dashboard_ninja/models/Kpi_mail.py deleted file mode 100644 index d296b9d..0000000 --- a/addons/ks_dashboard_ninja/models/Kpi_mail.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- - -from odoo import models, fields - - -class KpSendMail(models.Model): - _name = 'ks_dashboard_ninja.kpi_mail' - _description = 'Dashboard Ninja Kpi mail' - - - name = fields.Char(string="Email To:") diff --git a/addons/ks_dashboard_ninja/models/__init__.py b/addons/ks_dashboard_ninja/models/__init__.py deleted file mode 100644 index 679c939..0000000 --- a/addons/ks_dashboard_ninja/models/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from . import ks_dashboard_ninja -from . import ks_dashboard_ninja_items -from . import ks_item_action -from . import ks_child_dashboard -from . import ks_dashboard_filters -from . import ks_dashboard_templates -from . import ks_dn_to_do_item -from . import ks_import_dashboard -from . import Kpi_mail -from . import res_settings -from . import ks_ai_ninja_dashboard -from . import ks_ai_whole_dashboard -from . import ks_key_fetch -from . import ks_chat_channel -from . import base_model_extend - - diff --git a/addons/ks_dashboard_ninja/models/base_model_extend.py b/addons/ks_dashboard_ninja/models/base_model_extend.py deleted file mode 100644 index d6e5780..0000000 --- a/addons/ks_dashboard_ninja/models/base_model_extend.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -from odoo import models, api - - -class BaseExtend(models.AbstractModel): - _inherit = 'base' - - @api.model_create_multi - def create(self, vals): - recs = super(BaseExtend, self).create(vals) - if 'ir.' not in self._name and 'bus.' not in self._name and self.env.user.has_group('base.group_user'): - # items = self.env['ks_dashboard_ninja.item'].search( - # [['ks_model_id.model', '=', self._name]]) - # if items: - # online_partners = self.env["bus.presence"].sudo().search([('status', '=', 'online')]).mapped('user_id.partner_id').ids - # updates = [ for partner_id in online_partners] - self.env['bus.bus']._sendone('ks_notification', 'Update: Dashboard Items', {'model': self._name}) - return recs - - def write(self, vals): - recs = super(BaseExtend, self).write(vals) - if 'ir.' not in self._name and 'bus.' not in self._name and self.env.user.has_group('base.group_user') and 'res.partner' not in self._name: - # items = self.env['ks_dashboard_ninja.item'].search( - # [['ks_model_id.model', '=', self._name]]) - # if items: - # online_partner = self.env["bus.presence"].search([('status', '=', 'online')]).mapped('user_id.partner_id').ids - # updates = [[ - # (self._cr.dbname, 'res.partner', partner_id), - # {'type': 'ks_notification', 'model': self._name}, - # {'id': self.id} - # ] for partner_id in online_partner] - self.env['bus.bus']._sendone('ks_notification', 'Update: Dashboard Items', {'model': self._name}) - return recs \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py b/addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py deleted file mode 100644 index 9d78983..0000000 --- a/addons/ks_dashboard_ninja/models/ks_ai_ninja_dashboard.py +++ /dev/null @@ -1,402 +0,0 @@ -# -*- coding: utf-8 -*- - -import base64 -import io -import json -import logging -from urllib.parse import quote - -import pandas as pd -import requests -from gtts import gTTS -from odoo.exceptions import ValidationError -from odoo.tools import config - -from odoo import api, fields, models, _ - -_logger = logging.getLogger(__name__) - - -class KsDashboardNInjaAI(models.TransientModel): - _name = 'ks_dashboard_ninja.arti_int' - _description = 'AI Dashboard' - - 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 ID', - domain="[('access_ids','!=',False),('transient','=',False)," - "('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. ") - - ks_import_model = fields.Many2one('ir.model', string='Model', - domain="[('access_ids','!=',False),('transient','=',False)," - "('model','not ilike','base_import%'),('model','not 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. ") - ks_input_keywords = fields.Char("Ks Keywords") - ks_model_show = fields.Boolean(default = False, compute='_compute_show_model') - - @api.onchange('ks_input_keywords') - def _compute_show_model(self): - if self.ks_input_keywords and self.ks_type=="ks_keyword": - api_key = self.env['ir.config_parameter'].sudo().get_param('ks_dashboard_ninja.dn_api_key') - url = self.env['ir.config_parameter'].sudo().get_param('ks_dashboard_ninja.url') - if api_key and url: - json_data = {'name': api_key, - 'type': self.ks_type, - 'keyword': self.ks_input_keywords - } - url = url + "/api/v1/ks_dn_keyword_gen" - ks_response = requests.post(url, data=json_data) - if json.loads(ks_response.text) == False: - self.ks_model_show = True - else: - self.ks_model_show = False - else: - self.ks_model_show = False - else: - self.ks_model_show = False - - @api.model - def ks_get_keywords(self): - url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') - if url: - url = url + "/api/v1/ks_dn_get_keyword" - ks_response = requests.post(url) - if ks_response.status_code == 200: - return json.loads(ks_response.text) - else: - return [] - - - def ks_do_action(self): - headers = {"Content-Type": "application/json", - "Accept": "application/json", - "Catch-Control": "no-cache", - } - - if self.ks_import_model_id: - ks_model_name = self.ks_import_model_id.model - ks_fields = self.env[ks_model_name].fields_get() - ks_filtered_fields = {key: val for key, val in ks_fields.items() if val['type'] not in ['many2many', 'one2many', 'binary'] and'name' in val and val['name'] != 'id' and val['name'] != 'sequence' and val['store'] == True} - ks_fields_name = {val['name']:val['type'] for val in ks_filtered_fields.values()} - question = ("columns: "+ f"{ks_fields_name}") - - api_key = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.dn_api_key') - url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') - 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 - } - url = url+"/api/v1/ks_dn_main_api" - ks_ai_response = requests.post(url, data=json_data) - if ks_ai_response.status_code == 200: - ks_ai_response = json.loads(ks_ai_response.text) - # create dummy dash to create items on the dashboard, later deleted it. - ks_create_record = self.env['ks_dashboard_ninja.board'].create({ - 'name': 'AI dashboard', - 'ks_dashboard_menu_name': 'AI menu', - 'ks_dashboard_default_template': self.env.ref('ks_dashboard_ninja.ks_blank', False).id, - 'ks_dashboard_top_menu_id': self.env['ir.ui.menu'].search([('name', '=', 'My Dashboards')])[0].id, - }) - ks_dash_id = ks_create_record.id - - ks_result = self.env['ks_dashboard_ninja.item'].create_ai_dash(ks_ai_response, ks_dash_id, - ks_model_name) - context = {'ks_dash_id': self._context['ks_dashboard_id'], - 'ks_dash_name': self.env['ks_dashboard_ninja.board'].search([ - ('id','=',self._context['ks_dashboard_id'])]).name,'ks_delete_dash_id':ks_dash_id } - - # return client action created through js for AI dashboard to render items on dummy dashboard - if (ks_result == "success"): - return { - 'type': 'ir.actions.client', - 'name': 'Generate items with AI', - 'params': {'ks_dashboard_id': ks_create_record.id, 'explain_ai_whole': True}, - 'tag': 'ks_ai_dashboard_ninja', - 'context': context, - 'target':'new' - } - else: - self.env['ks_dashboard_ninja.board'].browse(ks_dash_id).unlink() - raise ValidationError(_("Items didn't render because AI provides invalid response for this model.Please try again")) - else: - raise ValidationError(_("AI Responds with the following status:- %s") % ks_ai_response.text) - else: - raise ValidationError(_("Please enter URL and API Key in General Settings")) - else: - raise ValidationError(_("Please enter the Model")) - - - - def ks_generate_item(self): - if self.ks_input_keywords: - api_key = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.dn_api_key') - url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') - if api_key and url: - json_data = {'name': api_key, - 'type': self.ks_type, - 'keyword':self.ks_input_keywords - } - url = url + "/api/v1/ks_dn_keyword_gen" - ks_response = requests.post(url, data=json_data) - else: - raise ValidationError(_("Please put API key and URL")) - if json.loads(ks_response.text) != False and ks_response.status_code==200 : - ks_ai_response = json.loads(ks_response.text) - ks_dash_id = self._context['ks_dashboard_id'] - ks_model_name = ks_ai_response[0]['model'] - ks_result = self.env['ks_dashboard_ninja.item'].create_ai_dash(ks_ai_response, ks_dash_id, - ks_model_name) - if ks_result == "success": - return{ - 'type': 'ir.actions.client', - 'tag': 'reload', - } - else: - raise ValidationError(_("Items didn't render, please try again!")) - else: - ks_model_name = self.ks_import_model.model - ks_fields = self.env[ks_model_name].fields_get() - ks_filtered_fields = {key: val for key, val in ks_fields.items() if - val['type'] not in ['many2many', 'one2many', 'binary'] and 'name' in val and val[ - 'name'] != 'id' and val['name'] != 'sequence' and val['store'] == True} - ks_fields_name = {val['name']: val['type'] for val in ks_filtered_fields.values()} - question = ("schema: " + f"{ks_fields_name}") - model =("model:" + f"{ks_model_name}") - api_key = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.dn_api_key') - url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') - if api_key and url: - json_data = {'name': api_key, - 'question': self.ks_input_keywords, - 'type':self.ks_type, - 'schema':question, - 'model':model, - 'url': self.env['ir.config_parameter'].sudo().get_param('web.base.url'), - 'db_name': self.env.cr.dbname - } - url = url + "/api/v1/ks_dn_main_api" - ks_ai_response = requests.post(url, data=json_data) - if ks_ai_response.status_code == 200: - ks_ai_response = json.loads(ks_ai_response.text) - ks_dash_id = self._context['ks_dashboard_id'] - ks_model_name = (ks_ai_response[0]['model']).lower() - if self.env['ir.model'].search([('model','=',ks_model_name)]).id or self.env['ir.model'].search([('name','=',ks_model_name)]).id: - if self.env['ir.model'].search([('name','=',ks_model_name)]).id: - ks_model_name = self.env['ir.model'].search([('name','=',ks_model_name)]).model - else: - ks_model_name = (ks_ai_response[0]['model']).lower() - ks_result = self.env['ks_dashboard_ninja.item'].create_ai_dash(ks_ai_response, ks_dash_id,ks_model_name) - if ks_result == "success": - return { - 'type': 'ir.actions.client', - 'tag': 'reload', - } - else: - raise ValidationError(_("Items didn't render, please try again!")) - else: - raise ValidationError(_("%s model does not exist.Please install")% ks_model_name) - else: - raise ValidationError( - _("AI Responds with the following status:- %s") % ks_ai_response.text) - - else: - raise ValidationError(_("Please enter URL and API Key in General Settings")) - 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'] or 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): #len(result) - if self.env.context.get('explain_items_with_ai', False): - self.env['ks_dashboard_ninja.board'].browse(dashboard_id).write({ - 'ks_ai_explain_dash': False - }) - else: - 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: - if self.env.context.get('explain_items_with_ai', False): - self.env['ks_dashboard_ninja.board'].browse(dashboard_id).write({ - 'ks_ai_explain_dash': False - }) - else: - self.env['ks_dashboard_ninja.board'].browse(dashboard_id).write({ - 'ks_ai_explain_dash': True - }) - return True - else: - return False - - def get_ai_explain(self, item_id): - print(item_id) - res = self.env['ks_dashboard_ninja.item'].browse(item_id).ks_ai_analysis - return res - - @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) - audio_data = io.BytesIO() - ks_myobj.write_to_fp(audio_data) - audio_data.seek(0) - binary_data = audio_data.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: - _logger.error(e) - raise ValidationError(_("Some problem in audio generation.")) - - else: - return False - - @api.model - def ks_gen_chat_res(self,**kwargs): - ks_question = kwargs.get('ks_question') - url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') + "/api/v1/get_sql_query" - data = { - "question": ks_question, - } - try: - ks_response = requests.post(url,data=data) - if (ks_response.status_code == 200): - ks_response = json.loads(ks_response.text)['response']['Query'] - return self.ks_gen_dataframe(ks_response,ks_question) - else: - _logger.error('Unexpected error occurs') - return False - except Exception as e: - _logger.error(e) - return False - - - - def ks_gen_dataframe(self,ks_query,question): - host = config.get('db_host', False) - user = quote(config.get('db_user', False)) - port = config.get('db_port', False) or 5432 - password = quote(config.get('db_password', False)) - db = config.get('db_name', False) or self.env.cr.dbname - if not all([host, user, port, password, db]): - _logger.error('some credentials are missing') - return False - else: - sql_uri = f"postgresql+psycopg2://{user}:{password}@{host}:{port}/{db}" - ks_fixed_url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') + "/api/v1/get_fixed_query" - try: - df = pd.read_sql(ks_query, sql_uri) - except Exception as e: - ks_query_data = { - 'query':ks_query, - 'error':e - } - fixed_query = requests.post(ks_fixed_url, data=ks_query_data) - if fixed_query.status_code == 200: - ks_corrected_query = fixed_query.text - df = pd.read_sql(ks_corrected_query, sql_uri) - else: - _logger.error('Error in generating Dataframe') - return False - if any(df.dtypes == 'datetime64[ns]'): - datetime_columns = [col for col in df.columns if df[col].dtype == 'datetime64[ns]'] - df[datetime_columns] = df[datetime_columns].astype(str) - - # Convert DataFrame to JSON - if len(df) >= 100: - df = df.head(100) - partial_data = True - - df_json = df.to_json(orient='records') - - ans = "As dataframe having more data to analyse we are not showing dataframe summary" - # Generate answer - if len(df) < 13: - ks_ans_url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') + "/api/v1/get_answer" - ks_ans_data = {'df':df.to_dict(orient='records'),'question':question} - ans = requests.post(ks_ans_url, json = ks_ans_data) - if ans.status_code == 200: - ans = ans.text - response_json = { - "Dataframe": df_json, - "Answer": ans, - } - else: - _logger.error('Error in generating answer') - return False - else: - response_json = { - "Dataframe": df_json, - "Answer": ans, - } - return response_json diff --git a/addons/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py b/addons/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py deleted file mode 100644 index 5ec2154..0000000 --- a/addons/ks_dashboard_ninja/models/ks_ai_whole_dashboard.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- - -import json -import logging - -import requests -from odoo.exceptions import ValidationError - -from odoo import fields, models, _ - -_logger = logging.getLogger(__name__) - - -class KsAIDashboardninja(models.TransientModel): - _name = 'ks_dashboard_ninja.ai_dashboard' - _description = 'AI Dashboard' - - ks_import_model_id = fields.Many2one('ir.model', string='Model', - domain="[('access_ids','!=',False),('transient','=',False)," - "('model','not ilike','base_import%'),('model','not 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. ", required=True) - - ks_dash_name = fields.Char(string="Dashboard Name", required=True, size=35) - ks_menu_name = fields.Char(string="Menu Name", required=True, size=35) - ks_top_menu_id = fields.Many2one('ir.ui.menu', - domain="[('parent_id','=',False)]", - string="Show Under Menu", required=True, - default=lambda self: self.env['ir.ui.menu'].search( - [('name', '=', 'My Dashboards')])[0]) - ks_template = fields.Many2one('ks_dashboard_ninja.board_template', - default=lambda self: self.env.ref('ks_dashboard_ninja.ks_blank', - False), - string="Dashboard Template") - - def ks_do_action(self): - headers = {"Content-Type": "application/json", - "Accept": "application/json", - "Catch-Control": "no-cache", - } - - if self.ks_import_model_id: - ks_model_name = self.ks_import_model_id.model - ks_fields = self.env[ks_model_name].fields_get() - ks_filtered_fields = {key: val for key, val in ks_fields.items() if val['type'] not in ['many2many', 'one2many', 'binary'] and'name' in val and val['name'] != 'id' and val['name'] != 'sequence' and val['store'] == True} - ks_fields_name = {val['name']:val['type'] for val in ks_filtered_fields.values()} - question = ("columns: "+ f"{ks_fields_name}") - - api_key = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.dn_api_key') - url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') - if api_key and url: - json_data = {'name': api_key, - 'question':question, - 'url':self.env['ir.config_parameter'].sudo().get_param('web.base.url'), - 'db_name':self.env.cr.dbname - } - url = url+"/api/v1/ks_dn_main_api" - ks_ai_response = requests.post(url, data=json_data) - if ks_ai_response.status_code == 200: - ks_ai_response = json.loads(ks_ai_response.text) - ks_create_record = self.env['ks_dashboard_ninja.board'].create({ - 'name': self.ks_dash_name, - 'ks_dashboard_menu_name': self.ks_menu_name, - 'ks_dashboard_default_template': self.ks_template.id, - 'ks_dashboard_top_menu_id': self.ks_top_menu_id.id, - }) - ks_dash_id = ks_create_record.id - - ks_result = self.env['ks_dashboard_ninja.item'].create_ai_dash(ks_ai_response, ks_dash_id, - ks_model_name) - - if (ks_result == "success"): - return { - 'type': 'ir.actions.client', - 'tag': 'reload', - } - else: - self.env['ks_dashboard_ninja.board'].browse(ks_dash_id).unlink() - raise ValidationError(_("Items didn't render, please try again!")) - else: - raise ValidationError(_("AI Responds with the following status:- %s") % ks_ai_response.text) - else: - raise ValidationError(_("Please enter URL and API Key in General Settings")) - else: - raise ValidationError(_("Please enter the Model")) - - - - diff --git a/addons/ks_dashboard_ninja/models/ks_chat_channel.py b/addons/ks_dashboard_ninja/models/ks_chat_channel.py deleted file mode 100644 index 564559b..0000000 --- a/addons/ks_dashboard_ninja/models/ks_chat_channel.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- - -from markupsafe import Markup - -from odoo import models, fields, _ - - -class ChatChannel(models.Model): - _inherit = 'discuss.channel' - - ks_dashboard_board_id = fields.Many2one('ks_dashboard_ninja.board') - ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item') - - def ks_chat_wizard_channel_id(self, **kwargs): - item_id = kwargs.get('item_id') - dashboard_id = kwargs.get('dashboard_id') - item_name = kwargs.get('item_name') - dashboard_name = kwargs.get('dashboard_name') - - channel = self.search([('ks_dashboard_item_id', '=', item_id)], limit=1) - - if not channel: - users = self.env['res.users'].search([('groups_id', 'in', self.env.ref('base.group_user').ids)]).mapped('partner_id.id') - - channel = self.create({ - 'name': f"{dashboard_name} - {item_name}", - 'ks_dashboard_board_id': dashboard_id, - 'ks_dashboard_item_id': item_id, - 'channel_member_ids': [(0, 0, {'partner_id': partner_id}) for partner_id in users] - }) - - notification = Markup('
%s
') % _("created this channel.") - channel.message_post(body=notification, message_type="notification", subtype_xmlid="mail.mt_comment") - self.env.user._bus_send_store(channel) - - return channel.id if channel else None diff --git a/addons/ks_dashboard_ninja/models/ks_child_dashboard.py b/addons/ks_dashboard_ninja/models/ks_child_dashboard.py deleted file mode 100644 index 1bc9593..0000000 --- a/addons/ks_dashboard_ninja/models/ks_child_dashboard.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -from odoo import models, fields, api - - -class KsDashboardNinjaBoardItemAction(models.Model): - _name = 'ks_dashboard_ninja.child_board' - _description = 'Dashboard Ninja Child Board' - - name = fields.Char() - ks_dashboard_ninja_id = fields.Many2one("ks_dashboard_ninja.board", string="Select Dashboard") - ks_gridstack_config = fields.Char('Item Configurations') - # ks_board_active_user_ids = fields.Many2many('res.users') - ks_active = fields.Boolean("Is Selected") - ks_dashboard_menu_name = fields.Char(string="Menu Name", related='ks_dashboard_ninja_id.ks_dashboard_menu_name', store=True) - board_type = fields.Selection([('default', 'Default'), ('child', 'Child')]) - company_id = fields.Many2one('res.company', required=True, default=lambda self: self.env.company) - ks_computed_group_access = fields.Many2many('res.groups', compute='_compute_ks_computed_group_access', store=True) - - @api.depends('ks_dashboard_ninja_id', 'ks_dashboard_ninja_id.ks_dashboard_group_access') - def _compute_ks_computed_group_access(self): - for record in self: - record.ks_computed_group_access = record.ks_dashboard_ninja_id.ks_dashboard_group_access - - def write(self,vals): - return super(KsDashboardNinjaBoardItemAction, self).write(vals) diff --git a/addons/ks_dashboard_ninja/models/ks_country_bounds.py b/addons/ks_dashboard_ninja/models/ks_country_bounds.py deleted file mode 100644 index e6aa3e9..0000000 --- a/addons/ks_dashboard_ninja/models/ks_country_bounds.py +++ /dev/null @@ -1,182 +0,0 @@ -country = { - 'AF': ('Afghanistan', (60.5284298033, 29.318572496, 75.1580277851, 38.4862816432)), - 'AO': ('Angola', (11.6400960629, -17.9306364885, 24.0799052263, -4.43802336998)), - 'AL': ('Albania', (19.3044861183, 39.624997667, 21.0200403175, 42.6882473822)), - 'AE': ('United Arab Emirates', (51.5795186705, 22.4969475367, 56.3968473651, 26.055464179)), - 'AR': ('Argentina', (-73.4154357571, -55.25, -53.628348965, -21.8323104794)), - 'AM': ('Armenia', (43.5827458026, 38.7412014837, 46.5057198423, 41.2481285671)), - 'AQ': ('Antarctica', (-180.0, -90.0, 180.0, -63.2706604895)), - 'TF': ('Fr. S. and Antarctic Lands', (68.72, -49.775, 70.56, -48.625)), - 'AU': ('Australia', (113.338953078, -43.6345972634, 153.569469029, -10.6681857235)), - 'AT': ('Austria', (9.47996951665, 46.4318173285, 16.9796667823, 49.0390742051)), - 'AZ': ('Azerbaijan', (44.7939896991, 38.2703775091, 50.3928210793, 41.8606751572)), - 'BI': ('Burundi', (29.0249263852, -4.49998341229, 30.752262811, -2.34848683025)), - 'BE': ('Belgium', (2.51357303225, 49.5294835476, 6.15665815596, 51.4750237087)), - 'BJ': ('Benin', (0.772335646171, 6.14215770103, 3.79711225751, 12.2356358912)), - 'BF': ('Burkina Faso', (-5.47056494793, 9.61083486576, 2.17710778159, 15.1161577418)), - 'BD': ('Bangladesh', (88.0844222351, 20.670883287, 92.6727209818, 26.4465255803)), - 'BG': ('Bulgaria', (22.3805257504, 41.2344859889, 28.5580814959, 44.2349230007)), - 'BS': ('Bahamas', (-78.98, 23.71, -77.0, 27.04)), - 'BA': ('Bosnia and Herz.', (15.7500260759, 42.65, 19.59976, 45.2337767604)), - 'BY': ('Belarus', (23.1994938494, 51.3195034857, 32.6936430193, 56.1691299506)), - 'BZ': ('Belize', (-89.2291216703, 15.8869375676, -88.1068129138, 18.4999822047)), - 'BO': ('Bolivia', (-69.5904237535, -22.8729187965, -57.4983711412, -9.76198780685)), - 'BR': ('Brazil', (-73.9872354804, -33.7683777809, -34.7299934555, 5.24448639569)), - 'BN': ('Brunei', (114.204016555, 4.007636827, 115.450710484, 5.44772980389)), - 'BT': ('Bhutan', (88.8142484883, 26.7194029811, 92.1037117859, 28.2964385035)), - 'BW': ('Botswana', (19.8954577979, -26.8285429827, 29.4321883481, -17.6618156877)), - 'CF': ('Central African Rep.', (14.4594071794, 2.2676396753, 27.3742261085, 11.1423951278)), - 'CA': ('Canada', (-140.99778, 41.6751050889, -52.6480987209, 83.23324)), - 'CH': ('Switzerland', (6.02260949059, 45.7769477403, 10.4427014502, 47.8308275417)), - 'CL': ('Chile', (-75.6443953112, -55.61183, -66.95992, -17.5800118954)), - 'CN': ('China', (73.6753792663, 18.197700914, 135.026311477, 53.4588044297)), - 'CI': ('Ivory Coast', (-8.60288021487, 4.33828847902, -2.56218950033, 10.5240607772)), - 'CM': ('Cameroon', (8.48881554529, 1.72767263428, 16.0128524106, 12.8593962671)), - 'CD': ('Congo (Kinshasa)', (12.1823368669, -13.2572266578, 31.1741492042, 5.25608775474)), - 'CG': ('Congo (Brazzaville)', (11.0937728207, -5.03798674888, 18.4530652198, 3.72819651938)), - 'CO': ('Colombia', (-78.9909352282, -4.29818694419, -66.8763258531, 12.4373031682)), - 'CR': ('Costa Rica', (-85.94172543, 8.22502798099, -82.5461962552, 11.2171192489)), - 'CU': ('Cuba', (-84.9749110583, 19.8554808619, -74.1780248685, 23.1886107447)), - 'CY': ('Cyprus', (32.2566671079, 34.5718694118, 34.0048808123, 35.1731247015)), - 'CZ': ('Czech Rep.', (12.2401111182, 48.5553052842, 18.8531441586, 51.1172677679)), - 'DE': ('Germany', (5.98865807458, 47.3024876979, 15.0169958839, 54.983104153)), - 'DJ': ('Djibouti', (41.66176, 10.9268785669, 43.3178524107, 12.6996385767)), - 'DK': ('Denmark', (8.08997684086, 54.8000145534, 12.6900061378, 57.730016588)), - 'DO': ('Dominican Rep.', (-71.9451120673, 17.598564358, -68.3179432848, 19.8849105901)), - 'DZ': ('Algeria', (-8.68439978681, 19.0573642034, 11.9995056495, 37.1183806422)), - 'EC': ('Ecuador', (-80.9677654691, -4.95912851321, -75.2337227037, 1.3809237736)), - 'EG': ('Egypt', (24.70007, 22.0, 36.86623, 31.58568)), - 'ER': ('Eritrea', (36.3231889178, 12.4554157577, 43.0812260272, 17.9983074)), - 'ES': ('Spain', (-9.39288367353, 35.946850084, 3.03948408368, 43.7483377142)), - 'EE': ('Estonia', (23.3397953631, 57.4745283067, 28.1316992531, 59.6110903998)), - 'ET': ('Ethiopia', (32.95418, 3.42206, 47.78942, 14.95943)), - 'FI': ('Finland', (20.6455928891, 59.846373196, 31.5160921567, 70.1641930203)), - 'FJ': ('Fiji', (-180.0, -18.28799, 180.0, -16.0208822567)), - 'FK': ('Falkland Is.', (-61.2, -52.3, -57.75, -51.1)), - 'FR': ('France', (-54.5247541978, 2.05338918702, 9.56001631027, 51.1485061713)), - 'GA': ('Gabon', (8.79799563969, -3.97882659263, 14.4254557634, 2.32675751384)), - 'GB': ('United Kingdom', (-7.57216793459, 49.959999905, 1.68153079591, 58.6350001085)), - 'GE': ('Georgia', (39.9550085793, 41.0644446885, 46.6379081561, 43.553104153)), - 'GH': ('Ghana', (-3.24437008301, 4.71046214438, 1.0601216976, 11.0983409693)), - 'GN': ('Guinea', (-15.1303112452, 7.3090373804, -7.83210038902, 12.5861829696)), - 'GM': ('Gambia', (-16.8415246241, 13.1302841252, -13.8449633448, 13.8764918075)), - 'GW': ('Guinea Bissau', (-16.6774519516, 11.0404116887, -13.7004760401, 12.6281700708)), - 'GQ': ('Eq. Guinea', (9.3056132341, 1.01011953369, 11.285078973, 2.28386607504)), - 'GR': ('Greece', (20.1500159034, 34.9199876979, 26.6041955909, 41.8269046087)), - 'GL': ('Greenland', (-73.297, 60.03676, -12.20855, 83.64513)), - 'GT': ('Guatemala', (-92.2292486234, 13.7353376327, -88.2250227526, 17.8193260767)), - 'GY': ('Guyana', (-61.4103029039, 1.26808828369, -56.5393857489, 8.36703481692)), - 'HN': ('Honduras', (-89.3533259753, 12.9846857772, -83.147219001, 16.0054057886)), - 'HR': ('Croatia', (13.6569755388, 42.47999136, 19.3904757016, 46.5037509222)), - 'HT': ('Haiti', (-74.4580336168, 18.0309927434, -71.6248732164, 19.9156839055)), - 'HU': ('Hungary', (16.2022982113, 45.7594811061, 22.710531447, 48.6238540716)), - 'ID': ('Indonesia', (95.2930261576, -10.3599874813, 141.03385176, 5.47982086834)), - 'IN': ('India', (68.1766451354, 7.96553477623, 97.4025614766, 35.4940095078)), - 'IE': ('Ireland', (-9.97708574059, 51.6693012559, -6.03298539878, 55.1316222195)), - 'IR': ('Iran', (44.1092252948, 25.0782370061, 63.3166317076, 39.7130026312)), - 'IQ': ('Iraq', (38.7923405291, 29.0990251735, 48.5679712258, 37.3852635768)), - 'IS': ('Iceland', (-24.3261840479, 63.4963829617, -13.609732225, 66.5267923041)), - 'IL': ('Israel', (34.2654333839, 29.5013261988, 35.8363969256, 33.2774264593)), - 'IT': ('Italy', (6.7499552751, 36.619987291, 18.4802470232, 47.1153931748)), - 'JM': ('Jamaica', (-78.3377192858, 17.7011162379, -76.1996585761, 18.5242184514)), - 'JO': ('Jordan', (34.9226025734, 29.1974946152, 39.1954683774, 33.3786864284)), - 'JP': ('Japan', (129.408463169, 31.0295791692, 145.543137242, 45.5514834662)), - 'KZ': ('Kazakhstan', (46.4664457538, 40.6623245306, 87.3599703308, 55.3852501491)), - 'KE': ('Kenya', (33.8935689697, -4.67677, 41.8550830926, 5.506)), - 'KG': ('Kyrgyzstan', (69.464886916, 39.2794632025, 80.2599902689, 43.2983393418)), - 'KH': ('Cambodia', (102.3480994, 10.4865436874, 107.614547968, 14.5705838078)), - 'KR': ('S. Korea', (126.117397903, 34.3900458847, 129.468304478, 38.6122429469)), - 'KW': ('Kuwait', (46.5687134133, 28.5260627304, 48.4160941913, 30.0590699326)), - 'LA': ('Laos', (100.115987583, 13.88109101, 107.564525181, 22.4647531194)), - 'LB': ('Lebanon', (35.1260526873, 33.0890400254, 36.6117501157, 34.6449140488)), - 'LR': ('Liberia', (-11.4387794662, 4.35575511313, -7.53971513511, 8.54105520267)), - 'LY': ('Libya', (9.31941084152, 19.58047, 25.16482, 33.1369957545)), - 'LK': ('Sri Lanka', (79.6951668639, 5.96836985923, 81.7879590189, 9.82407766361)), - 'LS': ('Lesotho', (26.9992619158, -30.6451058896, 29.3251664568, -28.6475017229)), - 'LT': ('Lithuania', (21.0558004086, 53.9057022162, 26.5882792498, 56.3725283881)), - 'LU': ('Luxembourg', (5.67405195478, 49.4426671413, 6.24275109216, 50.1280516628)), - 'LV': ('Latvia', (21.0558004086, 55.61510692, 28.1767094256, 57.9701569688)), - 'MA': ('Morocco', (-17.0204284327, 21.4207341578, -1.12455115397, 35.7599881048)), - 'MD': ('Moldova', (26.6193367856, 45.4882831895, 30.0246586443, 48.4671194525)), - 'MG': ('Madagascar', (43.2541870461, -25.6014344215, 50.4765368996, -12.0405567359)), - 'MX': ('Mexico', (-117.12776, 14.5388286402, -86.811982388, 32.72083)), - 'MK': ('Macedonia', (20.46315, 40.8427269557, 22.9523771502, 42.3202595078)), - 'ML': ('Mali', (-12.1707502914, 10.0963607854, 4.27020999514, 24.9745740829)), - 'MM': ('Myanmar', (92.3032344909, 9.93295990645, 101.180005324, 28.335945136)), - 'ME': ('Montenegro', (18.45, 41.87755, 20.3398, 43.52384)), - 'MN': ('Mongolia', (87.7512642761, 41.5974095729, 119.772823928, 52.0473660345)), - 'MZ': ('Mozambique', (30.1794812355, -26.7421916643, 40.7754752948, -10.3170960425)), - 'MR': ('Mauritania', (-17.0634232243, 14.6168342147, -4.92333736817, 27.3957441269)), - 'MW': ('Malawi', (32.6881653175, -16.8012997372, 35.7719047381, -9.23059905359)), - 'MY': ('Malaysia', (100.085756871, 0.773131415201, 119.181903925, 6.92805288332)), - 'NA': ('Namibia', (11.7341988461, -29.045461928, 25.0844433937, -16.9413428687)), - 'NC': ('New Caledonia', (164.029605748, -22.3999760881, 167.120011428, -20.1056458473)), - 'NE': ('Niger', (0.295646396495, 11.6601671412, 15.9032466977, 23.4716684026)), - 'NG': ('Nigeria', (2.69170169436, 4.24059418377, 14.5771777686, 13.8659239771)), - 'NI': ('Nicaragua', (-87.6684934151, 10.7268390975, -83.147219001, 15.0162671981)), - 'NL': ('Netherlands', (3.31497114423, 50.803721015, 7.09205325687, 53.5104033474)), - 'NO': ('Norway', (4.99207807783, 58.0788841824, 31.29341841, 80.6571442736)), - 'NP': ('Nepal', (80.0884245137, 26.3978980576, 88.1748043151, 30.4227169866)), - 'NZ': ('New Zealand', (166.509144322, -46.641235447, 178.517093541, -34.4506617165)), - 'OM': ('Oman', (52.0000098, 16.6510511337, 59.8080603372, 26.3959343531)), - 'PK': ('Pakistan', (60.8742484882, 23.6919650335, 77.8374507995, 37.1330309108)), - 'PA': ('Panama', (-82.9657830472, 7.2205414901, -77.2425664944, 9.61161001224)), - 'PE': ('Peru', (-81.4109425524, -18.3479753557, -68.6650797187, -0.0572054988649)), - 'PH': ('Philippines', (117.17427453, 5.58100332277, 126.537423944, 18.5052273625)), - 'PG': ('Papua New Guinea', (141.000210403, -10.6524760881, 156.019965448, -2.50000212973)), - 'PL': ('Poland', (14.0745211117, 49.0273953314, 24.0299857927, 54.8515359564)), - 'PR': ('Puerto Rico', (-67.2424275377, 17.946553453, -65.5910037909, 18.5206011011)), - 'KP': ('N. Korea', (124.265624628, 37.669070543, 130.780007359, 42.9853868678)), - 'PT': ('Portugal', (-9.52657060387, 36.838268541, -6.3890876937, 42.280468655)), - 'PY': ('Paraguay', (-62.6850571357, -27.5484990374, -54.2929595608, -19.3427466773)), - 'QA': ('Qatar', (50.7439107603, 24.5563308782, 51.6067004738, 26.1145820175)), - 'RO': ('Romania', (20.2201924985, 43.6884447292, 29.62654341, 48.2208812526)), - 'RU': ('Russia', (-180.0, 41.151416124, 180.0, 81.2504)), - 'RW': ('Rwanda', (29.0249263852, -2.91785776125, 30.8161348813, -1.13465911215)), - 'SA': ('Saudi Arabia', (34.6323360532, 16.3478913436, 55.6666593769, 32.161008816)), - 'SD': ('Sudan', (21.93681, 8.61972971293, 38.4100899595, 22.0)), - 'SS': ('S. Sudan', (23.8869795809, 3.50917, 35.2980071182, 12.2480077571)), - 'SN': ('Senegal', (-17.6250426905, 12.332089952, -11.4678991358, 16.5982636581)), - 'SB': ('Solomon Is.', (156.491357864, -10.8263672828, 162.398645868, -6.59933847415)), - 'SL': ('Sierra Leone', (-13.2465502588, 6.78591685631, -10.2300935531, 10.0469839543)), - 'SV': ('El Salvador', (-90.0955545723, 13.1490168319, -87.7235029772, 14.4241327987)), - 'SO': ('Somalia', (40.98105, -1.68325, 51.13387, 12.02464)), - 'RS': ('Serbia', (18.82982, 42.2452243971, 22.9860185076, 46.1717298447)), - 'SR': ('Suriname', (-58.0446943834, 1.81766714112, -53.9580446031, 6.0252914494)), - 'SK': ('Slovakia', (16.8799829444, 47.7584288601, 22.5581376482, 49.5715740017)), - 'SI': ('Slovenia', (13.6981099789, 45.4523163926, 16.5648083839, 46.8523859727)), - 'SE': ('Sweden', (11.0273686052, 55.3617373725, 23.9033785336, 69.1062472602)), - 'SZ': ('Swaziland', (30.6766085141, -27.2858794085, 32.0716654803, -25.660190525)), - 'SY': ('Syria', (35.7007979673, 32.312937527, 42.3495910988, 37.2298725449)), - 'TD': ('Chad', (13.5403935076, 7.42192454674, 23.88689, 23.40972)), - 'TG': ('Togo', (-0.0497847151599, 5.92883738853, 1.86524051271, 11.0186817489)), - 'TH': ('Thailand', (97.3758964376, 5.69138418215, 105.589038527, 20.4178496363)), - 'TJ': ('Tajikistan', (67.4422196796, 36.7381712916, 74.9800024759, 40.9602133245)), - 'TM': ('Turkmenistan', (52.5024597512, 35.2706639674, 66.5461503437, 42.7515510117)), - 'TL': ('East Timor', (124.968682489, -9.39317310958, 127.335928176, -8.27334482181)), - 'TT': ('Trinidad and Tobago', (-61.95, 10.0, -60.895, 10.89)), - 'TN': ('Tunisia', (7.52448164229, 30.3075560572, 11.4887874691, 37.3499944118)), - 'TR': ('Turkey', (26.0433512713, 35.8215347357, 44.7939896991, 42.1414848903)), - 'TW': ('Taiwan', (120.106188593, 21.9705713974, 121.951243931, 25.2954588893)), - 'TZ': ('Tanzania', (29.3399975929, -11.7209380022, 40.31659, -0.95)), - 'UG': ('Uganda', (29.5794661801, -1.44332244223, 35.03599, 4.24988494736)), - 'UA': ('Ukraine', (22.0856083513, 44.3614785833, 40.0807890155, 52.3350745713)), - 'UY': ('Uruguay', (-58.4270741441, -34.9526465797, -53.209588996, -30.1096863746)), - 'US': ('United States', (-171.791110603, 18.91619, -66.96466, 71.3577635769)), - 'UZ': ('Uzbekistan', (55.9289172707, 37.1449940049, 73.055417108, 45.5868043076)), - 'VE': ('Venezuela', (-73.3049515449, 0.724452215982, -59.7582848782, 12.1623070337)), - 'VN': ('Vietnam', (102.170435826, 8.59975962975, 109.33526981, 23.3520633001)), - 'VU': ('Vanuatu', (166.629136998, -16.5978496233, 167.844876744, -14.6264970842)), - 'PS': ('West Bank', (34.9274084816, 31.3534353704, 35.5456653175, 32.5325106878)), - 'YE': ('Yemen', (42.6048726743, 12.5859504257, 53.1085726255, 19.0000033635)), - 'ZA': ('South Africa', (16.3449768409, -34.8191663551, 32.830120477, -22.0913127581)), - 'ZM': ('Zambia', (21.887842645, -17.9612289364, 33.4856876971, -8.23825652429)), - 'ZW': ('Zimbabwe', (25.2642257016, -22.2716118303, 32.8498608742, -15.5077869605)), -} - - -def get_country_code(country_id): - if country_id in country.keys(): - return country.get(country_id) - else: - return {} diff --git a/addons/ks_dashboard_ninja/models/ks_dashboard_filters.py b/addons/ks_dashboard_ninja/models/ks_dashboard_filters.py deleted file mode 100644 index ceaee22..0000000 --- a/addons/ks_dashboard_ninja/models/ks_dashboard_filters.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- - -from odoo.addons.ks_dashboard_ninja.common_lib.filter_tools import replace_company_domain -from odoo.exceptions import ValidationError -from odoo.tools.safe_eval import safe_eval - -from odoo import models, fields, api, _ - - -class KsDashboardNinjaTemplate(models.Model): - _name = 'ks_dashboard_ninja.board_defined_filters' - _description = 'Dashboard Ninja Defined Filters' - - name = fields.Char('Filter Label') - ks_dashboard_board_id = fields.Many2one('ks_dashboard_ninja.board', string="Dashboard") - 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','_%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. ") - ks_domain = fields.Char(string="Domain", help="Define conditions for filter. ") - ks_domain_temp = fields.Char(string="Domain Substitute") - ks_model_name = fields.Char(related='ks_model_id.model', string="Model Name") - display_type = fields.Selection([ - ('line_section', "Section")], default=False, help="Technical field for UX purpose.") - sequence = fields.Integer(default=10, - help="Gives the sequence order when displaying a list of payment terms lines.") - ks_is_active = fields.Boolean(string="Active") - - @api.onchange('ks_domain') - def ks_domain_onchange(self): - for rec in self: - if rec.ks_model_id: - try: - ks_domain = rec.ks_domain - if ks_domain and "%UID" in ks_domain: - ks_domain = ks_domain.replace('"%UID"', str(self.env.user.id)) - if ks_domain and "%MYCOMPANY" in ks_domain: - ks_domain = replace_company_domain(ks_domain, self.env.company.id, self.env.companies.ids) - self.env[rec.ks_model_id.model].search_count(safe_eval(ks_domain)) - except Exception as e: - raise ValidationError(_("Something went wrong . Possibly it is due to wrong input type for domain")) - - @api.constrains('ks_domain', 'ks_model_id') - def ks_domain_check(self): - for rec in self: - if rec.ks_model_id and not rec.ks_domain: - raise ValidationError(_("Domain can not be empty")) - - - -class KsDashboardNinjaTemplate(models.Model): - _name = 'ks_dashboard_ninja.board_custom_filters' - _description = 'Dashboard Ninja Custom Filters' - - name = fields.Char("Filter Label") - ks_dashboard_board_id = fields.Many2one('ks_dashboard_ninja.board', string="Dashboard") - 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','_%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. ") - ks_domain_field_id = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id)," - "('name','!=','id'),('store','=',True)," - "('ttype', 'in', ['boolean', 'char', " - "'date', 'datetime', 'float', 'integer', 'html', 'many2many', " - "'many2one', 'monetary', 'one2many', 'text', 'selection'])]", - string="Domain Field") - - @api.onchange('ks_model_id') - def on_change_ks_model_id(self): - self.ks_domain_field_id = False - - -class KsDashboardNinjaTemplateFilters(models.Model): - _name = 'ks_dashboard_ninja.favourite_filters' - _description = 'Dashboard Ninja Favourite Filters' - - name = fields.Char("Filter Label") - ks_dashboard_board_id = fields.Many2one('ks_dashboard_ninja.board', string="Dashboard") - ks_filter = fields.Char("Filter") - ks_access_id = fields.Integer("Access Id") - ks_filter_type = fields.Char(default='favourite') - - _sql_constraints = [ - ('name_uniq', 'UNIQUE (name)', 'The name of the filter must be unique!'), - ] - - diff --git a/addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py b/addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py deleted file mode 100644 index 7c2f828..0000000 --- a/addons/ks_dashboard_ninja/models/ks_dashboard_ninja.py +++ /dev/null @@ -1,1502 +0,0 @@ -# -*- coding: utf-8 -*- - -import datetime -import json -from base64 import encodebytes -from collections import defaultdict - -from dateutil.parser import parse -from odoo.addons.ks_dashboard_ninja.common_lib.filter_tools import replace_company_domain -from odoo.addons.ks_dashboard_ninja.common_lib.ks_date_filter_selections import ks_get_date -from odoo.exceptions import ValidationError -from odoo.tools.image import image_data_uri -from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT -from odoo.tools.misc import file_open -from odoo.tools.safe_eval import safe_eval - -from odoo import models, fields, api, _ - - -class KsDashboardNinjaBoard(models.Model): - _name = 'ks_dashboard_ninja.board' - _description = 'Dashboard Ninja' - - name = fields.Char(string="Dashboard Name", required=True, size=35) - ks_dashboard_items_ids = fields.One2many('ks_dashboard_ninja.item', 'ks_dashboard_ninja_board_id', - string='Dashboard Items') - ks_dashboard_menu_name = fields.Char(string="Menu Name", size=35) - ks_dashboard_top_menu_id = fields.Many2one('ir.ui.menu', - domain="['|',('action','=',False),('parent_id','=',False)]", - string="Show Under Menu", - default=lambda self: self.env.ref('ks_dashboard_ninja.dashboards_menu_root',False)) - ks_dashboard_client_action_id = fields.Many2one('ir.actions.client') - ks_dashboard_menu_id = fields.Many2one('ir.ui.menu') - ks_dashboard_state = fields.Char() - ks_dashboard_active = fields.Boolean(string="Active", default=True) - ks_dashboard_group_access = fields.Many2many('res.groups', string="Group Access") - ks_dashboard_favourite_filters_ids = fields.One2many('ks_dashboard_ninja.favourite_filters', - 'ks_dashboard_board_id', string="Dashboard Favourite Filters") - - # DateFilter Fields - ks_dashboard_start_date = fields.Datetime(string="Start Date") - ks_dashboard_end_date = fields.Datetime(string="End Date") - ks_default_end_time = fields.Boolean(string="Default End Time") - ks_date_filter_selection = fields.Selection([ - ('l_none', 'All Time'), - ('l_day', 'Today'), - ('t_week', 'This Week'), - ('t_month', 'This Month'), - ('t_quarter', 'This Quarter'), - ('t_year', 'This Year'), - ('td_week', 'Week to Date'), - ('td_month', 'Month to Date'), - ('td_quarter', 'Quarter to Date'), - ('td_year', 'Year to Date'), - ('n_day', 'Next Day'), - ('n_week', 'Next Week'), - ('n_month', 'Next Month'), - ('n_quarter', 'Next Quarter'), - ('n_year', 'Next Year'), - ('ls_day', 'Last Day'), - ('ls_week', 'Last Week'), - ('ls_month', 'Last Month'), - ('ls_quarter', 'Last Quarter'), - ('ls_year', 'Last Year'), - ('l_week', 'Last 7 days'), - ('l_month', 'Last 30 days'), - ('l_quarter', 'Last 90 days'), - ('l_year', 'Last 365 days'), - ('ls_past_until_now', 'Past Till Now'), - ('ls_pastwithout_now', ' Past Excluding Today'), - ('n_future_starting_now', 'Future Starting Now'), - ('n_futurestarting_tomorrow', 'Future Starting Tomorrow'), - ('l_custom', 'Custom Filter'), - ], default='l_none', string="Default Date Filter") - - # for setting Global/Indian Format - ks_data_formatting = fields.Selection([ - ('global', 'Global'), - ('indian', 'Indian'), - ('exact', 'Exact') - ], string='Format') - - ks_gridstack_config = fields.Char('Item Configurations') - ks_dashboard_default_template = fields.Many2one('ks_dashboard_ninja.board_template', - default=lambda self: self.env.ref('ks_dashboard_ninja.ks_blank', - False), - string="Dashboard Template") - - ks_set_interval = fields.Selection([ - ('15000', '15 Seconds'), - ('30000', '30 Seconds'), - ('45000', '45 Seconds'), - ('60000', '1 minute'), - ('120000', '2 minute'), - ('300000', '5 minute'), - ('600000', '10 minute'), - ], string="Default Update Interval", help="Update Interval for new items only") - ks_dashboard_menu_sequence = fields.Integer(string="Menu Sequence", default=20, - help="Smallest sequence give high priority and Highest sequence give " - "low priority") - ks_child_dashboard_ids = fields.One2many('ks_dashboard_ninja.child_board', 'ks_dashboard_ninja_id') - ks_dashboard_defined_filters_ids = fields.One2many('ks_dashboard_ninja.board_defined_filters', - 'ks_dashboard_board_id', - string='Dashboard Predefined Filters') - ks_dashboard_custom_filters_ids = fields.One2many('ks_dashboard_ninja.board_custom_filters', - 'ks_dashboard_board_id', - string='Dashboard Custom Filters') - 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); - is_bookmarked = fields.Boolean(default=False) - - def _default_dashboard_image(self): - return image_data_uri(encodebytes(file_open('ks_dashboard_ninja/static/images/dashboardOverview/defaultDashboard.png', 'rb').read())) - - ks_dn_dashboard_image = fields.Binary('Dashboard Image', default=_default_dashboard_image, attachment=False) - - @api.constrains('ks_dashboard_start_date', 'ks_dashboard_end_date') - def ks_date_validation(self): - for rec in self: - if rec.ks_dashboard_start_date > rec.ks_dashboard_end_date: - raise ValidationError(_('Start date must be less than end date')) - - @api.model_create_multi - def create(self, vals): - records = super(KsDashboardNinjaBoard, self).create(vals) - for record in records: - if record.ks_dashboard_top_menu_id and record.ks_dashboard_menu_name: - action_id = { - 'name': record.ks_dashboard_menu_name + " Action", - 'res_model': 'ks_dashboard_ninja.board', - 'tag': 'ks_dashboard_ninja', - 'params': {'ks_dashboard_id': record.id, 'ks_dashboard_name': record.ks_dashboard_menu_name}, - } - record.ks_dashboard_client_action_id = self.env['ir.actions.client'].sudo().create(action_id) - group_ids = record.ks_dashboard_group_access.ids if record.ks_dashboard_group_access else [] - record.ks_dashboard_menu_id = self.env['ir.ui.menu'].sudo().create({ - 'name': record.ks_dashboard_menu_name, - 'active': record.ks_dashboard_active, - 'parent_id': record.ks_dashboard_top_menu_id.id, - 'action': "ir.actions.client," + str(record.ks_dashboard_client_action_id.id), - 'groups_id': group_ids, - 'sequence': record.ks_dashboard_menu_sequence - }) - # self.update_group_access_of_menus() - - if record.ks_dashboard_default_template and record.ks_dashboard_default_template.ks_item_count: - ks_gridstack_config = {} - template_data = json.loads(record.ks_dashboard_default_template.ks_gridstack_config) - for item_data in template_data: - if record.ks_dashboard_default_template.ks_template_type == 'ks_custom': - dashboard_item = self.env['ks_dashboard_ninja.item'].browse(int(item_data)).copy( - {'ks_dashboard_ninja_board_id': record.id}) - ks_gridstack_config[dashboard_item.id] = template_data[item_data] - else: - dashboard_item = self.env.ref(item_data['item_id']).copy({'ks_dashboard_ninja_board_id': record.id}) - ks_gridstack_config[dashboard_item.id] = item_data['data'] - record.ks_gridstack_config = json.dumps(ks_gridstack_config) - return records - - @api.onchange('ks_date_filter_selection') - def ks_date_filter_selection_onchange(self): - for rec in self: - if rec.ks_date_filter_selection and rec.ks_date_filter_selection != 'l_custom': - rec.ks_dashboard_start_date = False - rec.ks_dashboard_end_date = False - - - def write(self, vals): - if vals.get('ks_date_filter_selection', False) and vals.get('ks_date_filter_selection') != 'l_custom': - vals.update({ - 'ks_dashboard_start_date': False, - 'ks_dashboard_end_date': False - - }) - record = super(KsDashboardNinjaBoard, self).write(vals) - for rec in self: - if 'ks_dashboard_menu_name' in vals: - if self.env.ref('ks_dashboard_ninja.ks_my_default_dashboard_board', False) and self.env.ref( - 'ks_dashboard_ninja.ks_my_default_dashboard_board').sudo().id == rec.id: - if self.env.ref('ks_dashboard_ninja.board_menu_root', False): - self.env.ref('ks_dashboard_ninja.board_menu_root').sudo().name = vals['ks_dashboard_menu_name'] - else: - rec.ks_dashboard_menu_id.sudo().name = vals['ks_dashboard_menu_name'] - rec.ks_dashboard_client_action_id.name = vals['ks_dashboard_menu_name'] + " Action" - if 'ks_dashboard_group_access' in vals: - if self.env.ref('ks_dashboard_ninja.ks_my_default_dashboard_board', False) and self.env.ref('ks_dashboard_ninja.ks_my_default_dashboard_board').id == rec.id: - if self.env.ref('ks_dashboard_ninja.board_menu_root', False): - self.env.ref('ks_dashboard_ninja.board_menu_root').groups_id = vals['ks_dashboard_group_access'] - else: - rec.ks_dashboard_menu_id.sudo().groups_id = vals['ks_dashboard_group_access'] - admin_group_id = self.env.ref('base.group_system').id - menu_ids = rec.ks_dashboard_menu_id.sudo() - if not rec.ks_dashboard_group_access.ids: - menu_ids.groups_id = False - else: - menu_ids.groups_id = list(set(menu_ids.groups_id.ids + [admin_group_id])) - if 'ks_dashboard_active' in vals and rec.ks_dashboard_menu_id: - rec.ks_dashboard_menu_id.sudo().active = vals['ks_dashboard_active'] - - if 'ks_dashboard_top_menu_id' in vals: - rec.ks_dashboard_menu_id.write( - {'parent_id': vals['ks_dashboard_top_menu_id']} - ) - - if 'ks_dashboard_menu_sequence' in vals: - rec.ks_dashboard_menu_id.sudo().sequence = vals['ks_dashboard_menu_sequence'] - if 'name' in vals: - rec.ks_dashboard_client_action_id.sudo().name = vals['name'] - - return record - - def unlink(self): - if (self.env.ref('ks_dashboard_ninja.ks_my_default_dashboard_board', False) and - self.env.ref('ks_dashboard_ninja.ks_my_default_dashboard_board').id in self.ids): - raise ValidationError(_("Default Dashboard can't be deleted.")) - else: - for rec in self: - rec.ks_dashboard_client_action_id.sudo().unlink() - rec.ks_child_dashboard_ids.unlink() - rec.ks_dashboard_menu_id.sudo().unlink() - rec.ks_dashboard_items_ids.unlink() - res = super(KsDashboardNinjaBoard, self).unlink() - return res - - def ks_update_menu_id_old_db(self): - ks_records = self.search([('name','in',['Template1 Dashboard','Template2 Dashboard','Template3 Dashboard','My Dashboard'])]) - ks_menu_id = self.env.ref('ks_dashboard_ninja.dashboards_menu_root').id - for rec in ks_records: - if (rec.name == "My Dashboard" and rec.ks_dashboard_state == 'Locked') or(rec.name in ['Template1 Dashboard','Template2 Dashboard','Template3 Dashboard'] and rec.ks_dashboard_top_menu_id.name == 'My Dashboard'): - rec.ks_dashboard_top_menu_id = ks_menu_id - if not rec.ks_dashboard_menu_id: - action_id = { - 'name': rec.ks_dashboard_menu_name + " Action", - 'res_model': 'ks_dashboard_ninja.board', - 'tag': 'ks_dashboard_ninja', - 'params': {'ks_dashboard_id': rec.id, 'ks_dashboard_name': rec.ks_dashboard_menu_name}, - } - rec.ks_dashboard_client_action_id = self.env['ir.actions.client'].sudo().create(action_id) - - rec.ks_dashboard_menu_id = self.env['ir.ui.menu'].sudo().create({ - 'name': rec.ks_dashboard_menu_name, - 'active': rec.ks_dashboard_active, - 'parent_id': rec.ks_dashboard_top_menu_id.id, - 'action': "ir.actions.client," + str(rec.ks_dashboard_client_action_id.id), - 'groups_id': rec.ks_dashboard_group_access.ids if rec.ks_dashboard_group_access else False, - 'sequence': rec.ks_dashboard_menu_sequence if rec.ks_dashboard_menu_sequence else 10 - }) - - return True - - # def update_group_access_of_menus(self): - # all_dashboards = self.env['ks_dashboard_ninja.board'].search_read(domain=[], fields=['name', 'ks_dashboard_group_access']) - # admin_group_id = self.env.ref('base.group_system').id - # for dashboard in all_dashboards: - # current_groups = dashboard.get('ks_dashboard_group_access', []) - # current_groups.append(admin_group_id) - # updated_groups = list(set(current_groups)) - # current_groups = updated_groups - - - - def ks_get_grid_config(self): - default_grid_id = self.env['ks_dashboard_ninja.child_board'].search( - [['id', 'in', self.ks_child_dashboard_ids.ids], ['company_id', '=', self.env.company.id], - ['board_type', '=', 'default']]) - - if not default_grid_id: - default_grid_id = self.env['ks_dashboard_ninja.child_board'].create({ - "ks_gridstack_config": self.ks_gridstack_config, - "ks_dashboard_ninja_id": self.id, - "name": "Default Board Layout", - "company_id": self.env.company.id, - "board_type": "default", - }) - - return default_grid_id - - @api.model - def ks_fetch_dashboard_data(self, ks_dashboard_id, ks_item_domain=False): - """ - Return Dictionary of Dashboard Data. - :param ks_dashboard_id: Integer - :param ks_item_domain: List[List] - :return: dict - """ - - ks_dn_active_ids = [] - if self._context.get('ks_dn_active_ids'): - ks_dn_active_ids = self._context.get('ks_dn_active_ids') - - ks_dn_active_ids.append(ks_dashboard_id) - self = self.with_context( - ks_dn_active_ids=ks_dn_active_ids, - ) - - has_group_ks_dashboard_manager = self.env.user.has_group('ks_dashboard_ninja.ks_dashboard_ninja_group_manager') - ks_dashboard_rec = self.browse(ks_dashboard_id) - zooming_enabled = self.env['ir.config_parameter'].sudo().get_param('ks_dashboard_ninja.enable_chart_zoom') - dashboard_data = { - 'name': ks_dashboard_rec.name, - 'multi_layouts': ks_dashboard_rec.multi_layouts, - '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 - (fields.Datetime.context_timestamp(self, ks_dashboard_rec.ks_dashboard_start_date) if ks_dashboard_rec.ks_dashboard_end_date else False), - 'ks_dashboard_end_date': self._context.get('ksDateFilterEndDate', False) or - (fields.Datetime.context_timestamp(self, ks_dashboard_rec.ks_dashboard_end_date) if ks_dashboard_rec.ks_dashboard_end_date else False), - 'ks_date_filter_selection': self._context.get('ksDateFilterSelection', False) or self.browse( - ks_dashboard_id).ks_date_filter_selection, - 'ks_gridstack_config': "{}", - 'ks_set_interval': ks_dashboard_rec.ks_set_interval, - 'ks_data_formatting': ks_dashboard_rec.ks_data_formatting, - 'ks_dashboard_items_ids': ks_dashboard_rec.ks_dashboard_items_ids.ids, - 'ks_item_data': {}, - 'ks_child_boards': False, - 'ks_selected_board_id': False, - 'ks_default_end_time': ks_dashboard_rec.ks_default_end_time, - 'ks_dashboard_domain_data': ks_dashboard_rec.ks_prepare_dashboard_domain(), - 'ks_dashboard_pre_domain_filter': ks_dashboard_rec.ks_prepare_dashboard_pre_domain(), - 'ks_dashboard_custom_domain_filter': ks_dashboard_rec.ks_prepare_dashboard_custom_domain(), - 'ks_dashboard_favourite_filter': ks_dashboard_rec.ks_prepare_dashboard_favourite_filter(), - 'ks_item_model_relation': dict([(x['id'], [x['ks_model_name'], x['ks_model_name_2']]) for x in - ks_dashboard_rec.ks_dashboard_items_ids.read( - ['ks_model_name', 'ks_model_name_2'])]), - 'ks_model_item_relation': self.calc_model_item_relation(ks_dashboard_rec), - 'ks_ai_explain_dash':ks_dashboard_rec.ks_ai_explain_dash, - 'is_bookmarked': ks_dashboard_rec.is_bookmarked, - 'zooming_enabled': zooming_enabled - } - - default_grid_id = ks_dashboard_rec.ks_get_grid_config() - dashboard_data['ks_gridstack_config'] = default_grid_id[0].ks_gridstack_config - dashboard_data['ks_gridstack_config_id'] = default_grid_id[0].id - - if self.env['ks_dashboard_ninja.child_board'].search( - [['id', 'in', ks_dashboard_rec.ks_child_dashboard_ids.ids], ['company_id', '=', self.env.company.id], - ['board_type', '!=', 'default']], limit=1): - dashboard_data['ks_child_boards'] = { - 'ks_default': [ks_dashboard_rec.name, default_grid_id[0].ks_gridstack_config]} - selecred_rec = self.env['ks_dashboard_ninja.child_board'].search( - [['id', 'in', ks_dashboard_rec.ks_child_dashboard_ids.ids], ['ks_active', '=', True], - ['company_id', '=', self.env.company.id], ['board_type', '!=', 'default']], limit=1) - if selecred_rec: - dashboard_data['ks_selected_board_id'] = str(selecred_rec.id) - dashboard_data['ks_gridstack_config'] = selecred_rec.ks_gridstack_config - else: - dashboard_data['ks_selected_board_id'] = 'ks_default' - for rec in self.env['ks_dashboard_ninja.child_board'].search_read( - [['id', 'in', ks_dashboard_rec.ks_child_dashboard_ids.ids], - ['company_id', '=', self.env.company.id], ['board_type', '!=', 'default']], - ['name', 'ks_gridstack_config']): - dashboard_data['ks_child_boards'][str(rec['id'])] = [rec['name'], rec['ks_gridstack_config']] - ks_item_domain = ks_item_domain or [] - try: - items = self.ks_dashboard_items_ids.search( - [['ks_dashboard_ninja_board_id', '=', ks_dashboard_id]] + ks_item_domain).ids - except Exception as e: - items = self.ks_dashboard_items_ids.search( - [['ks_dashboard_ninja_board_id', '=', ks_dashboard_id]] + ks_item_domain).ids - dashboard_data['ks_dashboard_items_ids'] = items - return dashboard_data - - @api.model - def ks_fetch_item(self, item_list, ks_dashboard_id, params={}): - """ - :rtype: object - :param item_list: list of item ids. - :return: {'id':[item_data]} - """ - self = self.ks_set_date(ks_dashboard_id) - items = {} - item_model = self.env['ks_dashboard_ninja.item'] - for item_id in item_list: - item = self.ks_fetch_item_data(item_model.browse(item_id), params) - items[item['id']] = item - return items - - # fetching Item info (Divided to make function inherit easily) - def ks_fetch_item_data(self, rec, params={}): - """ - :rtype: object - :param item_id: item object - :return: object with formatted item data - """ - try: - ks_precision = self.sudo().env.ref('ks_dashboard_ninja.ks_dashboard_ninja_precision') - ks_precision_digits = ks_precision.digits - if ks_precision_digits < 0: - ks_precision_digits = 2 - if ks_precision_digits > 100: - ks_precision_digits = 2 - except Exception as e: - ks_precision_digits = 2 - - 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: - context = safe_eval(rec.ks_actions.context) - except Exception: - context = {} - - # Managing those views that have the access rights - ks_actions = rec.ks_actions.sudo() - action['name'] = ks_actions.name - action['type'] = ks_actions.type - action['res_model'] = ks_actions.res_model - action['views'] = ks_actions.views - action['view_mode'] = ks_actions.view_mode - action['search_view_id'] = ks_actions.search_view_id.id - action['context'] = context - action['target'] = 'current' - else: - action = False - ks_currency_symbol = False - ks_currency_position = False - if rec.ks_unit and rec.ks_unit_selection == 'monetary': - try: - ks_currency_symbol = self.env.user.company_id.currency_id.symbol - ks_currency_position = self.env.user.company_id.currency_id.position - except Exception as E: - ks_currency_symbol = False - ks_currency_position = False - - item = { - 'name': rec.name if rec.name else rec.ks_model_id.name if rec.ks_model_id else "Name", - '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_dashboard_name': rec.ks_dashboard_ninja_board_id.name, - 'ks_icon': rec.ks_icon, - 'ks_model_id': rec.ks_model_id.id, - 'ks_model_name': rec.ks_model_name, - 'ks_model_display_name': rec.ks_model_id.name, - 'ks_record_count_type': rec.ks_record_count_type, - 'ks_record_count': rec._ksGetRecordCount(item_domain1), - 'id': rec.id, - 'ks_layout': rec.ks_layout, - 'ks_icon_select': rec.ks_icon_select, - 'ks_default_icon': rec.ks_default_icon, - 'ks_default_icon_color': rec.ks_default_icon_color, - # Pro Fields - 'ks_dashboard_item_type': rec.ks_dashboard_item_type, - 'ks_chart_item_color': rec.ks_chart_item_color, - 'ks_chart_groupby_type': rec.ks_chart_groupby_type, - 'ks_chart_measure_field': rec.ks_chart_measure_field.ids, - 'ks_chart_measure_field_2': rec.ks_chart_measure_field_2.ids, - 'ks_chart_relation_groupby': rec.ks_chart_relation_groupby.id, - 'ks_chart_relation_groupby_name': rec.ks_chart_relation_groupby.name, - 'ks_chart_date_groupby': rec.ks_chart_date_groupby, - 'ks_chart_sub_groupby_type': rec.ks_chart_sub_groupby_type, - 'ks_chart_relation_sub_groupby': rec.ks_chart_relation_sub_groupby.id, - 'ks_chart_relation_sub_groupby_name': rec.ks_chart_relation_sub_groupby.name, - 'ks_chart_date_sub_groupby': rec.ks_chart_date_sub_groupby, - 'ks_record_field': rec.ks_record_field.id if rec.ks_record_field else False, - 'ks_chart_data': rec._ks_get_chart_data(item_domain1), - 'ks_list_view_data': rec._ksGetListViewData(item_domain1), - 'ks_chart_data_count_type': rec.ks_chart_data_count_type, - 'ks_bar_chart_stacked': rec.ks_bar_chart_stacked, - 'ks_semi_circle_chart': rec.ks_semi_circle_chart, - 'ks_list_view_type': rec.ks_list_view_type, - 'ks_list_view_group_fields': rec.ks_list_view_group_fields.ids if rec.ks_list_view_group_fields else False, - 'ks_previous_period': rec.ks_previous_period, - 'ks_kpi_data': rec._ksGetKpiData(item_domain1, item_domain2), - 'ks_goal_enable': rec.ks_goal_enable, - 'ks_model_id_2': rec.ks_model_id_2.id, - 'ks_record_field_2': rec.ks_record_field_2.id, - 'ks_data_comparison': rec.ks_data_comparison, - 'ks_target_view': rec.ks_target_view, - 'ks_date_filter_selection': rec.ks_date_filter_selection, - 'ks_show_data_value': rec.ks_show_data_value, - 'ks_show_records': rec.ks_show_records, - 'ks_unit': rec.ks_unit, - 'ks_unit_selection': rec.ks_unit_selection, - 'ks_chart_unit': rec.ks_chart_unit, - # 'action_id': rec.ks_actions.id if rec.ks_actions else False, - 'sequence': 0, - 'max_sequnce': len(rec.ks_action_lines) if rec.ks_action_lines else False, - 'action': action, - 'ks_hide_legend': rec.ks_hide_legend, - '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, - 'ks_record_data_limit': rec.ks_record_data_limit, - 'ks_chart_cumulative_field': rec.ks_chart_cumulative_field.ids, - 'ks_chart_cumulative': rec.ks_chart_cumulative, - 'ks_chart_is_cumulative': rec.ks_chart_is_cumulative, - 'ks_button_color': rec.ks_button_color, - 'ks_to_do_data': rec._ksGetToDOData(), - 'ks_multiplier_active': rec.ks_multiplier_active, - 'ks_multiplier': rec.ks_multiplier, - 'ks_goal_liness': True if rec.ks_goal_lines else False, - 'ks_currency_symbol': ks_currency_symbol, - 'ks_currency_id': self.env.user.company_id.currency_id.id, - 'ks_currency_position': ks_currency_position, - 'ks_precision_digits': ks_precision_digits if ks_precision_digits else 2, - 'ks_data_label_type': rec.ks_data_label_type, - 'ks_as_of_now': rec.ks_as_of_now, - '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_is_scatter_group': rec.ks_is_scatter_group, - '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_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, - 'item_data_source': rec.data_source - # 'ks_last_index':ks_last_index - # 'ks_id_name':','.join(ks_id_name) - } - return item - - def ks_set_date(self, ks_dashboard_id): - ks_dashboard_rec = self.browse(ks_dashboard_id) - if self._context.get('ksDateFilterSelection', False): - ks_date_filter_selection = self._context['ksDateFilterSelection'] - if ks_date_filter_selection == 'l_custom': - ks_start_dt_parse = parse(self._context['ksDateFilterStartDate']) - ks_end_dt_parse = parse(self._context['ksDateFilterEndDate']) - self = self.with_context( - ksDateFilterStartDate=fields.datetime.strptime(ks_start_dt_parse.strftime("%Y-%m-%d %H:%M:%S"), - "%Y-%m-%d %H:%M:%S")) - self = self.with_context( - ksDateFilterEndDate=fields.datetime.strptime(ks_end_dt_parse.strftime("%Y-%m-%d %H:%M:%S"), - "%Y-%m-%d %H:%M:%S")) - self = self.with_context(ksIsDefultCustomDateFilter=False) - - else: - ks_date_filter_selection = ks_dashboard_rec.ks_date_filter_selection - self = self.with_context(ksDateFilterStartDate=ks_dashboard_rec.ks_dashboard_start_date) - self = self.with_context(ksDateFilterEndDate=ks_dashboard_rec.ks_dashboard_end_date) - self = self.with_context(ksDateFilterSelection=ks_date_filter_selection) - self = self.with_context(ksIsDefultCustomDateFilter=True) - - if ks_date_filter_selection not in ['l_custom', 'l_none']: - ks_date_data = ks_get_date(ks_date_filter_selection, self, 'datetime') - self = self.with_context(ksDateFilterStartDate=ks_date_data["selected_start_date"]) - self = self.with_context(ksDateFilterEndDate=ks_date_data["selected_end_date"]) - - return self - - def calc_model_item_relation(self, ks_dashboard_rec): - model_items_dict = defaultdict(list) - - for x in ks_dashboard_rec.ks_dashboard_items_ids.read(['ks_model_name', 'ks_model_name_2']): - if x['ks_model_name']: - model_items_dict[x['ks_model_name']].append(x['id']) - if x['ks_model_name_2']: - model_items_dict[x['ks_model_name_2']].append(x['id']) - - model_items_dict = dict(model_items_dict) - return model_items_dict - - @api.model - def ks_get_list_view_data_offset(self, ks_dashboard_item_id, offset, dashboard_id, params={}): - item_domain = params.get('ks_domain_1', []) - self = self.ks_set_date(dashboard_id) - item = self.ks_dashboard_items_ids.browse(ks_dashboard_item_id) - - return item.ks_get_next_offset(ks_dashboard_item_id, offset, item_domain) - - def fetch_dashboard_overview(self, **kwargs): - - ks_board_model = self.env['ks_dashboard_ninja.board'] - ks_board_item_model = self.env['ks_dashboard_ninja.item'] - dashboards = ks_board_model.search_read(domain=[], fields=['name', 'is_bookmarked', 'ks_dn_dashboard_image']) - bookmarked_dashboards = ks_board_model.search_count([('is_bookmarked', '=', True)]) - chart_count = 0 - map_count = ks_board_item_model.search_count([('ks_dashboard_item_type', '=', 'ks_map_view')]) - dashboards_info = {} - list_view_count = ks_board_item_model.search_count([('ks_dashboard_item_type', '=', 'ks_list_view'), ('ks_dashboard_ninja_board_id', '!=', False)]) - chart_list = ['ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_pie_chart', - 'ks_doughnut_chart', - 'ks_polarArea_chart', 'ks_radialBar_chart', 'ks_scatter_chart', 'ks_funnel_chart', - 'ks_bullet_chart', 'ks_flower_view', 'ks_radar_view'] - - for dashboard in dashboards: - charts = ks_board_item_model.search_count( - [('ks_dashboard_ninja_board_id', '=', dashboard['id']), ('ks_dashboard_item_type', 'in', chart_list)]) - chart_count += charts - dashboards_info[dashboard['id']] = { - 'chartCount': charts, - 'name': dashboard['name'], - 'id': dashboard['id'], - 'is_bookmarked': dashboard['is_bookmarked'], - 'image': dashboard['ks_dn_dashboard_image'], - } - - return { - 'overviewInfo': [len(dashboards), chart_count, map_count, bookmarked_dashboards, list_view_count], - 'dashboardsInfo': dashboards_info, - 'user_name': self.env.user.name, - 'isManager': self.env.user.has_group('ks_dashboard_ninja.ks_dashboard_ninja_group_manager') - } - - def update_bookmarks(self, *args): - self.ensure_one() - self.is_bookmarked = not self.is_bookmarked - return [self.env['ks_dashboard_ninja.board'].search_count([('is_bookmarked', '=', True)]), self.is_bookmarked] - - def ks_view_items_view(self): - self.ensure_one() - return { - 'name': _("Dashboard Items"), - 'res_model': 'ks_dashboard_ninja.item', - 'view_mode': 'list,form', - 'view_type': 'form', - 'views': [(False, 'list'), (False, 'form')], - 'type': 'ir.actions.act_window', - 'domain': [('ks_dashboard_ninja_board_id', '!=', False)], - 'search_view_id': self.env.ref('ks_dashboard_ninja.ks_item_search_view').id, - 'context': { - 'search_default_ks_dashboard_ninja_board_id': self.id, - 'group_by': 'ks_dashboard_ninja_board_id', - }, - 'help': _('''

- You can find all items related to Dashboard Here.

- '''), - - } - - def ks_export_item(self, item_id): - return { - 'ks_file_format': 'ks_dashboard_ninja_item_export', - 'item': self.ks_export_item_data(self.ks_dashboard_items_ids.browse(int(item_id))) - } - - # fetching Item info (Divided to make function inherit easily) - def ks_export_item_data(self, rec): - ks_timezone = self._context.get('tz') or self.env.user.tz - ks_chart_measure_field = [] - ks_chart_measure_field_2 = [] - if rec.ks_many2many_field_ordering: - ks_many2many_field_ordering = json.loads(rec.ks_many2many_field_ordering) - else: - ks_many2many_field_ordering = {} - if ks_many2many_field_ordering.get('ks_list_view_fields', False): - ks_list_view_fields_list = self.env['ir.model.fields'].search([('id', 'in', - ks_many2many_field_ordering.get('ks_list_view_fields', False))]) - if ks_many2many_field_ordering.get('ks_list_view_group_fields', False): - ks_list_view_group_fields_list = self.env['ir.model.fields'].search([('id', 'in', - ks_many2many_field_ordering.get('ks_list_view_group_fields', False))]) - if ks_many2many_field_ordering.get('ks_chart_measure_field', False): - ks_chart_measure_field_list = self.env['ir.model.fields'].search([('id', 'in', - ks_many2many_field_ordering.get('ks_chart_measure_field', False))]) - if ks_many2many_field_ordering.get('ks_chart_measure_field_2', False): - ks_chart_measure_field_2_list = self.env['ir.model.fields'].search([('id', 'in', - ks_many2many_field_ordering.get('ks_chart_measure_field_2', False))]) - - try: - for res in ks_chart_measure_field_list: - ks_chart_measure_field.append(res.name) - except Exception as E: - ks_chart_measure_field = [] - try: - for res in ks_chart_measure_field_2_list: - ks_chart_measure_field_2.append(res.name) - except Exception as E: - ks_chart_measure_field_2 = [] - ks_multiplier_fields = [] - ks_multiplier_value = [] - if rec.ks_multiplier_lines: - for ress in rec.ks_multiplier_lines.ks_multiplier_fields: - ks_multiplier_fields.append(ress.name) - for ks_val in rec.ks_multiplier_lines: - ks_multiplier_value.append(ks_val.ks_multiplier_value) - - ks_list_view_group_fields = [] - try: - for res in ks_list_view_group_fields_list: - ks_list_view_group_fields.append(res.name) - except Exception as e: - ks_list_view_group_fields = [] - ks_goal_lines = [] - for res in rec.ks_goal_lines: - goal_line = { - 'ks_goal_date': datetime.datetime.strftime(res.ks_goal_date, "%Y-%m-%d"), - 'ks_goal_value': res.ks_goal_value, - } - ks_goal_lines.append(goal_line) - ks_dn_header_lines = [] - for res in rec.ks_dn_header_lines: - ks_dn_header_line = { - 'ks_to_do_header': res.ks_to_do_header - } - - if res.ks_to_do_description_lines: - ks_to_do_description_lines = [] - for ks_description_line in res.ks_to_do_description_lines: - description_line = { - 'ks_description': ks_description_line.ks_description, - 'ks_active': ks_description_line.ks_active, - } - ks_to_do_description_lines.append(description_line) - ks_dn_header_line[res.ks_to_do_header] = ks_to_do_description_lines - ks_dn_header_lines.append(ks_dn_header_line) - - ks_action_lines = [] - for res in rec.ks_action_lines: - action_line = { - 'ks_item_action_field': res.ks_item_action_field.name, - 'ks_item_action_date_groupby': res.ks_item_action_date_groupby, - 'ks_chart_type': res.ks_chart_type, - 'ks_sort_by_field': res.ks_sort_by_field.name, - '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 = [] - for res in rec.ks_multiplier_lines: - ks_multiplier_line = { - 'ks_multiplier_fields': res.ks_multiplier_fields.id, - 'ks_multiplier_value': res.ks_multiplier_value, - 'ks_dashboard_item_id': rec.id, - 'ks_model_id': rec.ks_model_id.id - } - ks_multiplier_lines.append(ks_multiplier_line) - - ks_list_view_field = [] - try: - for res in ks_list_view_fields_list: - ks_list_view_field.append(res.name) - except Exception as e: - ks_list_view_field = [] - val = str(rec.id) - keys_data = {} - selecred_rec = self.env['ks_dashboard_ninja.child_board'].search( - [['id', 'in', rec.ks_dashboard_ninja_board_id.ks_child_dashboard_ids.ids], ['ks_active', '=', True], - ['company_id', '=', self.env.company.id]], limit=1) - if rec.ks_dashboard_ninja_board_id.ks_gridstack_config: - keys_data = json.loads(rec.ks_dashboard_ninja_board_id.ks_gridstack_config) - elif selecred_rec and selecred_rec.ks_gridstack_config: - keys_data = json.loads(selecred_rec.ks_gridstack_config) - elif rec.ks_dashboard_ninja_board_id.ks_child_dashboard_ids[0].ks_gridstack_config: - keys_data = json.loads(rec.ks_dashboard_ninja_board_id.ks_child_dashboard_ids[0].ks_gridstack_config) - elif self._context.get('gridstack_config', False): - keys_data = self._context.get('gridstack_config', False) - else: - if rec.grid_corners: - keys_data = {rec.id: json.loads(rec.grid_corners.replace("\'", "\""))} - keys_list = keys_data.keys() - grid_corners = {} - if val in keys_list: - grid_corners = keys_data.get(str(val)) - - item = { - 'name': rec.name if rec.name else rec.ks_model_id.name if rec.ks_model_id else "Name", - '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, - 'ks_icon': str(rec.ks_icon) if rec.ks_icon else False, - 'ks_id': rec.id, - 'ks_model_id': rec.ks_model_name, - 'ks_record_count': rec.ks_record_count, - 'ks_layout': rec.ks_layout, - 'ks_icon_select': rec.ks_icon_select, - 'ks_default_icon': rec.ks_default_icon, - 'ks_default_icon_color': rec.ks_default_icon_color, - 'ks_record_count_type': rec.ks_record_count_type, - # Pro Fields - 'ks_dashboard_item_type': rec.ks_dashboard_item_type, - 'ks_chart_item_color': rec.ks_chart_item_color, - 'ks_chart_groupby_type': rec.ks_chart_groupby_type, - 'ks_chart_relation_groupby': rec.ks_chart_relation_groupby.name, - 'ks_chart_date_groupby': rec.ks_chart_date_groupby, - 'ks_record_field': rec.ks_record_field.name, - 'ks_chart_sub_groupby_type': rec.ks_chart_sub_groupby_type, - 'ks_chart_relation_sub_groupby': rec.ks_chart_relation_sub_groupby.name, - 'ks_chart_date_sub_groupby': rec.ks_chart_date_sub_groupby, - 'ks_chart_data_count_type': rec.ks_chart_data_count_type, - 'ks_chart_measure_field': ks_chart_measure_field, - 'ks_chart_measure_field_2': ks_chart_measure_field_2, - 'ks_list_view_fields': ks_list_view_field, - 'ks_list_view_group_fields': ks_list_view_group_fields, - 'ks_list_view_type': rec.ks_list_view_type, - 'ks_record_data_limit': rec.ks_record_data_limit, - 'ks_sort_by_order': rec.ks_sort_by_order, - 'ks_sort_by_field': rec.ks_sort_by_field.name, - 'ks_date_filter_field': rec.ks_date_filter_field.name, - 'ks_goal_enable': rec.ks_goal_enable, - 'ks_standard_goal_value': rec.ks_standard_goal_value, - 'ks_goal_liness': ks_goal_lines, - 'ks_date_filter_selection': rec.ks_date_filter_selection, - 'ks_item_start_date': rec.ks_item_start_date.strftime( - DEFAULT_SERVER_DATETIME_FORMAT) if rec.ks_item_start_date else False, - 'ks_item_end_date': rec.ks_item_end_date.strftime( - DEFAULT_SERVER_DATETIME_FORMAT) if rec.ks_item_end_date else False, - 'ks_date_filter_selection_2': rec.ks_date_filter_selection_2, - 'ks_item_start_date_2': rec.ks_item_start_date_2.strftime( - DEFAULT_SERVER_DATETIME_FORMAT) if rec.ks_item_start_date_2 else False, - 'ks_item_end_date_2': rec.ks_item_end_date_2.strftime( - DEFAULT_SERVER_DATETIME_FORMAT) if rec.ks_item_end_date_2 else False, - 'ks_previous_period': rec.ks_previous_period, - 'ks_target_view': rec.ks_target_view, - 'ks_data_comparison': rec.ks_data_comparison, - 'ks_record_count_type_2': rec.ks_record_count_type_2, - 'ks_record_field_2': rec.ks_record_field_2.name, - 'ks_model_id_2': rec.ks_model_id_2.model, - 'ks_date_filter_field_2': rec.ks_date_filter_field_2.name, - 'ks_action_liness': ks_action_lines, - 'ks_compare_period': rec.ks_compare_period, - 'ks_year_period': rec.ks_year_period, - 'ks_compare_period_2': rec.ks_compare_period_2, - 'ks_year_period_2': rec.ks_year_period_2, - 'ks_domain_2': rec.ks_domain_2, - 'ks_show_data_value': rec.ks_show_data_value, - 'ks_list_target_deviation_field': rec.ks_list_target_deviation_field.name, - 'ks_unit': rec.ks_unit, - 'ks_show_records': rec.ks_show_records, - 'ks_hide_legend': rec.ks_hide_legend, - 'ks_radial_legend': rec.ks_radial_legend, - 'ks_fill_temporal': rec.ks_fill_temporal, - 'ks_domain_extension': rec.ks_domain_extension, - 'ks_unit_selection': rec.ks_unit_selection, - 'ks_chart_unit': rec.ks_chart_unit, - 'ks_bar_chart_stacked': rec.ks_bar_chart_stacked, - 'ks_goal_bar_line': rec.ks_goal_bar_line, - 'ks_actions': rec.ks_actions.xml_id if rec.ks_actions else False, - 'ks_client_action': rec.ks_client_action.xml_id if rec.ks_client_action else False, - 'ks_is_client_action': rec.ks_is_client_action, - 'ks_export_all_records': rec.ks_export_all_records, - 'ks_record_data_limit_visibility': rec.ks_record_data_limit_visibility, - 'ks_data_format': rec.ks_data_format, - 'ks_pagination_limit': rec.ks_pagination_limit, - 'ks_chart_cumulative_field': rec.ks_chart_cumulative_field.ids, - 'ks_chart_cumulative': rec.ks_chart_cumulative, - 'ks_button_color': rec.ks_button_color, - 'ks_dn_header_line': ks_dn_header_lines, - 'ks_semi_circle_chart': rec.ks_semi_circle_chart, - 'ks_multiplier_active': rec.ks_multiplier_active, - 'ks_multiplier': rec.ks_multiplier, - 'ks_multiplier_lines': ks_multiplier_lines if ks_multiplier_lines else False, - 'ks_many2many_field_ordering': rec.ks_many2many_field_ordering, - '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_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, - - } - if grid_corners: - item.update({ - 'grid_corners': grid_corners, - }) - return item - - def ks_open_import(self, **kwargs): - action = self.env['ir.actions.act_window']._for_xml_id('ks_dashboard_ninja.ks_import_dashboard_action') - return action - - def ks_open_setting(self, **kwargs): - action = self.env['ir.actions.act_window']._for_xml_id('ks_dashboard_ninja.board_form_tree_action_window') - # action['res_id'] = self.id - # action['target'] = 'new' - # action['context'] = {'form_view_ref':'ks_dashboard_ninja.board_form'} - # action['view_mode']='form' - return action - - # def ks_delete_dashboard(self): - # if str(self.id) in self.ks_dashboard_default_template: - # raise ValidationError(_('You cannot delete any default template')) - # else: - # self.search([('id', '=', self.id)]).unlink() - # return { - # 'type': 'ir.actions.client', - # 'name': "My Dashboard", - # 'tag': 'dashboard_ninja', - # # 'id': {} - # } - def save_dashboard_image(self, *args, **kwargs): - self.ensure_one() - image = kwargs.get('image') - if image: - self.ks_dn_dashboard_image = image - - def ks_create_dashboard(self): - action = self.env['ir.actions.act_window']._for_xml_id('ks_dashboard_ninja.board_form_tree_action_window') - action['target'] = 'new' - return action - - def ks_import_item(self, dashboard_id, **kwargs): - try: - # ks_dashboard_data = json.loads(file) - file = kwargs.get('file', False) - ks_dashboard_file_read = json.loads(file) - except Exception: - raise ValidationError(_("This file is not supported")) - - if 'ks_file_format' in ks_dashboard_file_read and ks_dashboard_file_read[ - 'ks_file_format'] == 'ks_dashboard_ninja_item_export': - item = ks_dashboard_file_read['item'] - else: - raise ValidationError(_("Current Json File is not properly formatted according to Dashboard Ninja Model.")) - - item['ks_dashboard_ninja_board_id'] = int(dashboard_id) - item['ks_company_id'] = False - self.ks_create_item(item) - - return "Success" - - @api.model - def ks_dashboard_export(self, ks_dashboard_ids, **kwargs): - ks_dashboard_data = [] - ks_dashboard_export_data = {} - if kwargs.get('dashboard_id'): - ks_dashboard_ids = '['+str(ks_dashboard_ids)+']' - ks_dashboard_ids = json.loads(ks_dashboard_ids) - for ks_dashboard_id in ks_dashboard_ids: - dash = self.search([('id', '=', ks_dashboard_id)]) - selecred_rec = self.env['ks_dashboard_ninja.child_board'].search( - [['id', 'in', dash.ks_child_dashboard_ids.ids], ['ks_active', '=', True], - ['company_id', '=', self.env.company.id]], limit=1) - ks_dashboard_rec = self.browse(ks_dashboard_id) - if selecred_rec: - name = selecred_rec.name - grid_conf = selecred_rec.ks_gridstack_config - elif dash.ks_child_dashboard_ids: - name = dash.display_name - grid_conf = dash.ks_child_dashboard_ids[0].ks_gridstack_config - else: - name = dash.name - grid_conf = dash.ks_gridstack_config - dashboard_data = self.ks_prepare_export_data_vals(ks_dashboard_rec, grid_conf=grid_conf) - if selecred_rec: - dashboard_data['name'] = selecred_rec.name - dashboard_data['ks_gridstack_config'] = selecred_rec.ks_gridstack_config - elif len(ks_dashboard_rec.ks_child_dashboard_ids) > 1: - dashboard_data['name'] = ks_dashboard_rec.ks_child_dashboard_ids[0].name - dashboard_data['ks_gridstack_config'] = ks_dashboard_rec.ks_child_dashboard_ids[0].ks_gridstack_config - if dashboard_data['name'] == 'Default Board Layout': - dashboard_data['name'] = ks_dashboard_rec.ks_dashboard_menu_name - if len(ks_dashboard_rec.ks_dashboard_items_ids) < 1: - dashboard_data['ks_item_data'] = False - else: - items = [] - for rec in ks_dashboard_rec.ks_dashboard_items_ids: - item = self.ks_export_item_data(rec) - items.append(item) - - dashboard_data['ks_item_data'] = items - ks_dashboard_data.append(dashboard_data) - - ks_dashboard_export_data = { - 'ks_file_format': 'ks_dashboard_ninja_export_file', - 'ks_dashboard_data': ks_dashboard_data - } - return ks_dashboard_export_data - - def ks_prepare_export_data_vals(self, ks_dashboard_rec, grid_conf=None,): - dashboard_data = { - 'name': ks_dashboard_rec.name, - 'ks_dashboard_menu_name': ks_dashboard_rec.ks_dashboard_menu_name, - 'ks_gridstack_config': grid_conf if grid_conf else '{}', - 'ks_set_interval': ks_dashboard_rec.ks_set_interval, - 'ks_date_filter_selection': ks_dashboard_rec.ks_date_filter_selection, - 'ks_dashboard_start_date': ks_dashboard_rec.ks_dashboard_start_date, - 'ks_dashboard_end_date': ks_dashboard_rec.ks_dashboard_end_date, - 'ks_dashboard_top_menu_id': ks_dashboard_rec.ks_dashboard_top_menu_id.id, - 'ks_data_formatting': ks_dashboard_rec.ks_data_formatting, - } - return dashboard_data - - @api.model - def ks_import_dashboard(self, file, menu_id): - try: - # ks_dashboard_data = json.loads(file) - ks_dashboard_file_read = json.loads(file) - except Exception: - raise ValidationError(_("This file is not supported")) - - if 'ks_file_format' in ks_dashboard_file_read and ks_dashboard_file_read[ - 'ks_file_format'] == 'ks_dashboard_ninja_export_file': - ks_dashboard_data = ks_dashboard_file_read['ks_dashboard_data'] - for i in range(len(ks_dashboard_data)): - if 'ks_set_interval' in ks_dashboard_data[i].keys() and ks_dashboard_data[i].get('ks_item_data', False): - # del ks_dashboard_data[i]['ks_set_interval'] - for j in range(len(ks_dashboard_data[i].get('ks_item_data', False))): - if 'ks_update_items_data' in ks_dashboard_data[i].get('ks_item_data', False)[j].keys(): - del ks_dashboard_data[i].get('ks_item_data', False)[j]['ks_update_items_data'] - if 'ks_auto_update_type' in ks_dashboard_data[i].get('ks_item_data', False)[j].keys(): - del ks_dashboard_data[i].get('ks_item_data', False)[j]['ks_auto_update_type'] - if 'ks_show_live_pop_up' in ks_dashboard_data[i].get('ks_item_data', False)[j].keys(): - del ks_dashboard_data[i].get('ks_item_data', False)[j]['ks_show_live_pop_up'] - else: - raise ValidationError(_("Current Json File is not properly formatted according to Dashboard Ninja Model.")) - - ks_dashboard_key = ['name', 'ks_dashboard_menu_name', 'ks_gridstack_config'] - ks_dashboard_item_key = ['ks_model_id', 'ks_chart_measure_field', 'ks_list_view_fields', 'ks_record_field', - 'ks_chart_relation_groupby', 'ks_id'] - - # Fetching dashboard model info - for data in ks_dashboard_data: - if not all(key in data for key in ks_dashboard_key): - raise ValidationError( - _("Current Json File is not properly formatted according to Dashboard Ninja Model.")) - ks_dashboard_top_menu_id = data.get('ks_dashboard_top_menu_id', False) - if ks_dashboard_top_menu_id: - try: - self.env['ir.ui.menu'].browse(ks_dashboard_top_menu_id).name - ks_dashboard_top_menu_id = self.env['ir.ui.menu'].browse(ks_dashboard_top_menu_id) - except Exception: - ks_dashboard_top_menu_id = False - vals = self.ks_prepare_import_data_vals(data, menu_id) - # Creating Dashboard - dashboard_id = self.create(vals) - - if data['ks_gridstack_config']: - ks_gridstack_config = safe_eval(data['ks_gridstack_config']) - ks_grid_stack_config = {} - - item_ids = [] - item_new_ids = [] - ks_skiped = False - if data['ks_item_data']: - # Fetching dashboard item info - ks_skiped = 0 - for item in data['ks_item_data']: - item['ks_company_id'] = False - if not all(key in item for key in ks_dashboard_item_key): - raise ValidationError( - _("Current Json File is not properly formatted according to Dashboard Ninja Model.")) - - # Creating dashboard items - item['ks_dashboard_ninja_board_id'] = dashboard_id.id - item_ids.append(item['ks_id']) - del item['ks_id'] - - if 'ks_data_calculation_type' in item: - if item['ks_data_calculation_type'] == 'custom': - del item['ks_data_calculation_type'] - del item['ks_custom_query'] - del item['ks_xlabels'] - del item['ks_ylabels'] - del item['ks_list_view_layout'] - ks_item = self.ks_create_item(item) - item_new_ids.append(ks_item.id) - else: - ks_skiped += 1 - else: - ks_item = self.ks_create_item(item) - item_new_ids.append(ks_item.id) - - for id_index, id in enumerate(item_ids): - if data['ks_gridstack_config'] and str(id) in ks_gridstack_config: - ks_grid_stack_config[str(item_new_ids[id_index])] = ks_gridstack_config[str(id)] - # if id_index in item_new_ids: - - self.browse(dashboard_id.id).write({ - 'ks_gridstack_config': json.dumps(ks_grid_stack_config) - }) - - if ks_skiped: - return { - 'ks_skiped_items': ks_skiped, - } - - return "Success" - # separate function to make item for import - - def ks_prepare_import_data_vals(self, data, menu_id): - vals = { - 'name': data['name'], - 'ks_dashboard_menu_name': data['ks_dashboard_menu_name'], - 'ks_dashboard_top_menu_id': menu_id.id if menu_id else self.env.ref( - "ks_dashboard_ninja.board_menu_root").id, - 'ks_dashboard_active': True, - 'ks_gridstack_config': data['ks_gridstack_config'], - 'ks_dashboard_default_template': self.env.ref("ks_dashboard_ninja.ks_blank").id, - 'ks_dashboard_group_access': False, - 'ks_set_interval': data['ks_set_interval'], - 'ks_date_filter_selection': data['ks_date_filter_selection'], - 'ks_dashboard_start_date': data['ks_dashboard_start_date'], - 'ks_dashboard_end_date': data['ks_dashboard_end_date'], - } - return vals - - def ks_create_item(self, item): - model = self.env['ir.model'].search([('model', '=', item['ks_model_id'])]) - - if not model and not item['ks_dashboard_item_type'] == 'ks_to_do': - raise ValidationError(_( - "Please Install the Module which contains the following Model : %s " % item['ks_model_id'])) - - ks_model_name = item['ks_model_id'] - - ks_goal_lines = item['ks_goal_liness'].copy() if item.get('ks_goal_liness', False) else False - ks_action_lines = item['ks_action_liness'].copy() if item.get('ks_action_liness', False) else False - ks_multiplier_lines = item['ks_multiplier_lines'].copy() if item.get('ks_multiplier_lines', False) else False - ks_dn_header_line = item['ks_dn_header_line'].copy() if item.get('ks_dn_header_line', False) else False - - # Creating dashboard items - item = self.ks_prepare_item(item) - - if 'ks_goal_liness' in item: - del item['ks_goal_liness'] - if 'ks_id' in item: - del item['ks_id'] - if 'ks_action_liness' in item: - del item['ks_action_liness'] - if 'ks_icon' in item: - item['ks_icon_select'] = "Default" - item['ks_icon'] = False - if 'ks_dn_header_line' in item: - del item['ks_dn_header_line'] - if 'ks_multiplier_lines' in item: - del item['ks_multiplier_lines'] - - ks_item = self.env['ks_dashboard_ninja.item'].create(item) - - if ks_goal_lines and len(ks_goal_lines) != 0: - for line in ks_goal_lines: - line['ks_goal_date'] = datetime.datetime.strptime(line['ks_goal_date'].split(" ")[0], - '%Y-%m-%d') - line['ks_dashboard_item'] = ks_item.id - self.env['ks_dashboard_ninja.item_goal'].create(line) - - if ks_dn_header_line and len(ks_dn_header_line) != 0: - for line in ks_dn_header_line: - ks_line = {} - ks_line['ks_to_do_header'] = line.get('ks_to_do_header') - ks_line['ks_dn_item_id'] = ks_item.id - ks_dn_header_id = self.env['ks_to.do.headers'].create(ks_line) - if line.get(line.get('ks_to_do_header'), False): - for ks_task in line.get(line.get('ks_to_do_header')): - ks_task['ks_to_do_header_id'] = ks_dn_header_id.id - self.env['ks_to.do.description'].create(ks_task) - - if ks_action_lines and len(ks_action_lines) != 0: - - for line in ks_action_lines: - if line['ks_sort_by_field']: - ks_sort_by_field = line['ks_sort_by_field'] - ks_sort_record_id = self.env['ir.model.fields'].search( - [('model', '=', ks_model_name), ('name', '=', ks_sort_by_field)]) - if ks_sort_record_id: - line['ks_sort_by_field'] = ks_sort_record_id.id - else: - line['ks_sort_by_field'] = False - if line['ks_item_action_field']: - ks_item_action_field = line['ks_item_action_field'] - ks_record_id = self.env['ir.model.fields'].search( - [('model', '=', ks_model_name), ('name', '=', ks_item_action_field)]) - if ks_record_id: - line['ks_item_action_field'] = ks_record_id.id - line['ks_dashboard_item_id'] = ks_item.id - self.env['ks_dashboard_ninja.item_action'].create(line) - - if ks_multiplier_lines and len(ks_multiplier_lines) != 0: - for rec in ks_multiplier_lines: - ks_multiplier_field = rec['ks_multiplier_fields'] - ks_multiplier_field_id = self.env['ir.model.fields'].search( - [('model', '=', ks_model_name), ('id', '=', ks_multiplier_field)]) - if ks_multiplier_field: - rec['ks_multiplier_fields'] = ks_multiplier_field_id.id - rec['ks_dashboard_item_id'] = ks_item.id - self.env['ks_dashboard_item.multiplier'].create(rec) - - return ks_item - - def ks_prepare_item(self, item): - try: - ks_measure_field_ids = [] - ks_measure_field_2_ids = [] - ks_many2many_field_ordering = item['ks_many2many_field_ordering'] if item.get('ks_many2many_field_ordering', False) else False - ks_list_view_group_fields_name = False - ks_list_view_fields_name = False - ks_chart_measure_field_name = False - ks_chart_measure_field_2_name = False - if ks_many2many_field_ordering: - ks_many2many_field_ordering = json.loads(ks_many2many_field_ordering) - ks_list_view_group_fields_name = ks_many2many_field_ordering.get('ks_list_view_group_fields_name', False) - ks_list_view_fields_name = ks_many2many_field_ordering.get('ks_list_view_fields_name', False) - ks_chart_measure_field_name = ks_many2many_field_ordering.get('ks_chart_measure_field_name', False) - ks_chart_measure_field_2_name = ks_many2many_field_ordering.get('ks_chart_measure_field_2_name', False) - ks_chart_measure_field = item['ks_chart_measure_field'] - if ks_chart_measure_field_name and len(ks_chart_measure_field_name)>0: - ks_chart_measure_field = ks_chart_measure_field_name - for ks_measure in ks_chart_measure_field: - ks_measure_id = self.env['ir.model.fields'].search( - [('name', '=', ks_measure), ('model', '=', item['ks_model_id'])]) - if ks_measure_id: - ks_measure_field_ids.append(ks_measure_id.id) - item['ks_chart_measure_field'] = [(6, 0, ks_measure_field_ids)] - ks_chart_measure_field_2 = item['ks_chart_measure_field_2'] - if ks_chart_measure_field_name and len(ks_chart_measure_field_name) > 0: - ks_chart_measure_field_2 = ks_chart_measure_field_2_name - for ks_measure in ks_chart_measure_field_2: - ks_measure_id = self.env['ir.model.fields'].search( - [('name', '=', ks_measure), ('model', '=', item['ks_model_id'])]) - if ks_measure_id: - ks_measure_field_2_ids.append(ks_measure_id.id) - item['ks_chart_measure_field_2'] = [(6, 0, ks_measure_field_2_ids)] - - ks_list_view_group_fields_ids = [] - ks_list_view_group_fields = item['ks_list_view_group_fields'] - if ks_list_view_group_fields_name and len(ks_list_view_group_fields_name) > 0: - ks_list_view_group_fields = ks_list_view_group_fields_name - for ks_measure in ks_list_view_group_fields: - ks_measure_id = self.env['ir.model.fields'].search( - [('name', '=', ks_measure), ('model', '=', item['ks_model_id'])]) - - if ks_measure_id: - ks_list_view_group_fields_ids.append(ks_measure_id.id) - item['ks_list_view_group_fields'] = [(6, 0, ks_list_view_group_fields_ids)] - - ks_list_view_field_ids = [] - - ks_list_view_fields = item['ks_list_view_fields'] - if ks_list_view_fields_name and len(ks_list_view_fields_name) > 0: - ks_list_view_fields = ks_list_view_group_fields_name - for ks_list_field in ks_list_view_fields: - ks_list_field_id = self.env['ir.model.fields'].search( - [('name', '=', ks_list_field), ('model', '=', item['ks_model_id'])]) - if ks_list_field_id: - ks_list_view_field_ids.append(ks_list_field_id.id) - item['ks_list_view_fields'] = [(6, 0, ks_list_view_field_ids)] - - if item['ks_record_field']: - ks_record_field = item['ks_record_field'] - ks_record_id = self.env['ir.model.fields'].search( - [('name', '=', ks_record_field), ('model', '=', item['ks_model_id'])]) - if ks_record_id: - item['ks_record_field'] = ks_record_id.id - else: - item['ks_record_field'] = False - - if item['ks_date_filter_field']: - ks_date_filter_field = item['ks_date_filter_field'] - ks_record_id = self.env['ir.model.fields'].search( - [('name', '=', ks_date_filter_field), ('model', '=', item['ks_model_id'])]) - if ks_record_id: - item['ks_date_filter_field'] = ks_record_id.id - else: - item['ks_date_filter_field'] = False - - if item['ks_chart_relation_groupby']: - ks_group_by = item['ks_chart_relation_groupby'] - ks_record_id = self.env['ir.model.fields'].search( - [('name', '=', ks_group_by), ('model', '=', item['ks_model_id'])]) - if ks_record_id: - item['ks_chart_relation_groupby'] = ks_record_id.id - else: - item['ks_chart_relation_groupby'] = False - - if item['ks_chart_relation_sub_groupby']: - ks_group_by = item['ks_chart_relation_sub_groupby'] - ks_chart_relation_sub_groupby = self.env['ir.model.fields'].search( - [('name', '=', ks_group_by), ('model', '=', item['ks_model_id'])]) - if ks_chart_relation_sub_groupby: - item['ks_chart_relation_sub_groupby'] = ks_chart_relation_sub_groupby.id - else: - item['ks_chart_relation_sub_groupby'] = False - - 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_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'])]) - if ks_record_id: - item['ks_scatter_measure_x_id'] = ks_record_id.id - else: - 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 - - # Sort by field : Many2one Entery - if item['ks_sort_by_field']: - ks_group_by = item['ks_sort_by_field'] - ks_sort_by_field = self.env['ir.model.fields'].search( - [('name', '=', ks_group_by), ('model', '=', item['ks_model_id'])]) - if ks_sort_by_field: - item['ks_sort_by_field'] = ks_sort_by_field.id - else: - item['ks_sort_by_field'] = False - - if item['ks_list_target_deviation_field']: - ks_list_target_deviation_field = item['ks_list_target_deviation_field'] - record_id = self.env['ir.model.fields'].search( - [('name', '=', ks_list_target_deviation_field), ('model', '=', item['ks_model_id'])]) - if record_id: - item['ks_list_target_deviation_field'] = record_id.id - else: - item['ks_list_target_deviation_field'] = False - - ks_model_id = self.env['ir.model'].search([('model', '=', item['ks_model_id'])]).id - - if item.get("ks_actions"): - ks_action = self.env.ref(item["ks_actions"], False) - if ks_action: - item["ks_actions"] = ks_action.id - else: - item["ks_actions"] = False - if item.get("ks_client_action"): - ks_action = self.env.ref(item["ks_client_action"], False) - if ks_action: - item["ks_client_action"] = ks_action.id - else: - item["ks_client_action"] = False - - if (item['ks_model_id_2']): - ks_model_2 = item['ks_model_id_2'].replace(".", "_") - ks_model_id_2 = self.env['ir.model'].search([('model', '=', item['ks_model_id_2'])]).id - if item['ks_record_field_2']: - ks_record_field = item['ks_record_field_2'] - ks_record_id = self.env['ir.model.fields'].search( - [('model', '=', item['ks_model_id_2']), ('name', '=', ks_record_field)]) - - if ks_record_id: - item['ks_record_field_2'] = ks_record_id.id - else: - item['ks_record_field_2'] = False - if item['ks_date_filter_field_2']: - ks_record_id = self.env['ir.model.fields'].search( - [('model', '=', item['ks_model_id_2']), ('name', '=', item['ks_date_filter_field_2'])]) - - if ks_record_id: - item['ks_date_filter_field_2'] = ks_record_id.id - else: - item['ks_date_filter_field_2'] = False - - item['ks_model_id_2'] = ks_model_id_2 - else: - item['ks_date_filter_field_2'] = False - item['ks_record_field_2'] = False - - item['ks_model_id'] = ks_model_id - - item['ks_goal_liness'] = False - item['ks_item_start_date'] = item['ks_item_start_date'] if \ - item['ks_item_start_date'] else False - item['ks_item_end_date'] = item['ks_item_end_date'] if \ - item['ks_item_end_date'] else False - item['ks_item_start_date_2'] = item['ks_item_start_date_2'] if \ - item['ks_item_start_date_2'] else False - item['ks_item_end_date_2'] = item['ks_item_end_date_2'] if \ - item['ks_item_end_date_2'] else False - - return item - except Exception as e: - raise ValidationError('JSON file not supported.') - @api.model - def update_child_board(self, action, dashboard_id, data): - dashboard_id = self.browse(dashboard_id) - selecred_rec = self.env['ks_dashboard_ninja.child_board'].search( - [['id', 'in', dashboard_id.ks_child_dashboard_ids.ids], - ['company_id', '=', self.env.company.id], ['ks_active', '=', True]], limit=1) - if action == 'create': - dashboard_id.ks_child_dashboard_ids.write({'ks_active': False}) - result = self.env['ks_dashboard_ninja.child_board'].create(data) - result = result.id - elif action == 'update': - # result = dashboard_id.ks_child_dashboard_ids.search([['ks_active', '=', True]]).write({'ks_active': False}) - if data['ks_selected_board_id'] != 'ks_default': - selecred_rec.ks_active = False - result = dashboard_id.ks_child_dashboard_ids.browse(int(data['ks_selected_board_id'])).write( - {'ks_active': True}) - else: - result = dashboard_id.ks_child_dashboard_ids.search([['ks_active', '=', True]]).write( - {'ks_active': False}) - for i in dashboard_id.ks_child_dashboard_ids: - if i.name == 'Default Board Layout': - i.ks_active = True - return result - - def ks_prepare_dashboard_domain(self): - pre_defined_filter_ids = self.env['ks_dashboard_ninja.board_defined_filters'].search( - [['id', 'in', self.ks_dashboard_defined_filters_ids.ids], '|', ['ks_is_active', '=', True], - ['display_type', '=', 'line_section']], order='sequence') - data = {} - filter_model_ids = pre_defined_filter_ids.mapped('ks_model_id').ids - for model_id in filter_model_ids: - filter_ids = self.env['ks_dashboard_ninja.board_defined_filters'].search( - [['id', 'in', pre_defined_filter_ids.ids], '|', ['ks_model_id', '=', model_id], - ['display_type', '=', 'line_section']], - order='sequence') - connect_symbol = '|' - for rec in filter_ids: - if rec.display_type == 'line_section': - connect_symbol = '&' - - if data.get(rec.ks_model_id.model) and rec.ks_domain: - data[rec.ks_model_id.model]['domain'] = data[rec.ks_model_id.model]['domain'] + safe_eval( - rec.ks_domain) - data[rec.ks_model_id.model]['domain'].insert(0, connect_symbol) - elif rec.ks_model_id.model: - ks_domain = rec.ks_domain - if ks_domain and "%UID" in ks_domain: - ks_domain = ks_domain.replace('"%UID"', str(self.env.user.id)) - if ks_domain and "%MYCOMPANY" in ks_domain: - ks_domain = replace_company_domain(ks_domain, self.env.company.id, self.env.companies.ids) - data[rec.ks_model_id.model] = { - 'domain': safe_eval(ks_domain) if ks_domain else [], - 'ks_domain_index_data': [], - 'model_name': rec.ks_model_id.name, - 'item_ids': self.env['ks_dashboard_ninja.item'].search( - [['id', 'in', self.ks_dashboard_items_ids.ids], '|', - ['ks_model_id', '=', rec.ks_model_id.id], ['ks_model_id_2', '=', rec.ks_model_id.id]]).ids - } - - return data - - def ks_prepare_dashboard_pre_domain(self): - data = {} - pre_defined_filter_ids = self.env['ks_dashboard_ninja.board_defined_filters'].search( - [['id', 'in', self.ks_dashboard_defined_filters_ids.ids]], order='sequence') - categ_seq = 1 - for rec in pre_defined_filter_ids: - if rec.display_type == 'line_section': - categ_seq = categ_seq + 1 - ks_domain = rec.ks_domain - if ks_domain and "%UID" in ks_domain: - ks_domain = ks_domain.replace('"%UID"', str(self.env.user.id)) - if ks_domain and "%MYCOMPANY" in ks_domain: - ks_domain = replace_company_domain(ks_domain, self.env.company.id, self.env.companies.ids) - - data[rec['id']] = { - 'id': rec.id, - 'name': rec.name, - 'model': rec.ks_model_id.model, - 'model_name': rec.ks_model_id.name, - 'active': rec.ks_is_active, - 'categ': rec.ks_model_id.model + '_' + str(categ_seq) if rec.display_type != 'line_section' else 0, - 'type': 'filter' if rec.display_type != 'line_section' else 'separator', - 'domain': safe_eval(ks_domain) if ks_domain else [], - 'sequence': rec.sequence - } - return data - - def ks_prepare_dashboard_custom_domain(self): - custom_filter_ids = self.env['ks_dashboard_ninja.board_custom_filters'].search( - [['id', 'in', self.ks_dashboard_custom_filters_ids.ids]], order='name') - data = {} - for rec in custom_filter_ids: - data[str(rec.id)] = { - 'id': rec.id, - 'name': rec.name, - 'model': rec.ks_model_id.model, - 'model_name': rec.ks_model_id.name, - 'field_name': rec.ks_domain_field_id.name, - 'type': rec.ks_domain_field_id.ttype, - 'relation': rec.ks_domain_field_id.relation if rec.ks_domain_field_id.ttype in ['many2many', 'many2one', - 'one2many'] else False, - 'selection': [] - } - if rec.ks_domain_field_id.ttype == 'selection': - selection_list = self.env[rec.ks_model_id.model].fields_get(allfields=[rec.ks_domain_field_id.name])[ - rec.ks_domain_field_id.name]['selection'] - data[str(rec.id)]['selection'] = selection_list - return data - - def ks_prepare_dashboard_favourite_filter(self): - data = {} - ks_favourite_filter_ids = self.env['ks_dashboard_ninja.favourite_filters'].search( - [['id', 'in', self.ks_dashboard_favourite_filters_ids.ids], '|', ['ks_access_id', '=', self.env.user.id], - ['ks_access_id', '=', 0]], order='create_date') - for rec in ks_favourite_filter_ids: - data[rec.name] = {'id': rec.id, - 'ks_filter': json.loads(rec.ks_filter), - 'name': rec.name, - 'type': rec.ks_filter_type, - 'ks_access_id': True if rec.ks_access_id else False, - } - return data diff --git a/addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py b/addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py deleted file mode 100644 index dc20e0d..0000000 --- a/addons/ks_dashboard_ninja/models/ks_dashboard_ninja_items.py +++ /dev/null @@ -1,4632 +0,0 @@ -# -*- coding: utf-8 -*- - -import ast -import binascii -import csv -import datetime as dt -import json -import logging -import os -import tempfile -from collections import defaultdict -from datetime import datetime -from datetime import timedelta - -import babel -import dateutil -import pandas as pd -from odoo.tools import sql, SQL -import pytz -from dateutil import relativedelta -from odoo import models, fields, api, _ -from odoo.addons.ks_dashboard_ninja.common_lib.ks_date_filter_selections import ks_get_date, ks_convert_into_utc, \ - ks_convert_into_local -from odoo.exceptions import ValidationError, UserError -from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT -from odoo.tools.safe_eval import safe_eval -from odoo.addons.ks_dashboard_ninja.common_lib.filter_tools import replace_company_domain - - -from .ks_country_bounds import get_country_code - -_logger = logging.getLogger("DS_NINJA") -# TODO : Check all imports if needed - - -read = fields.Many2one.read - - - -def ks_read(self, records): - if self.name == 'ks_list_view_fields' or self.name == 'ks_list_view_group_fields' or \ - self.name == 'ks_chart_measure_field' or self.name == 'ks_chart_measure_field_2': - comodel = records.env[self.comodel_name] - - # String domains are supposed to be dynamic and evaluated on client-side - # only (thus ignored here). - domain = self.domain if isinstance(self.domain, list) else [] - query = comodel._where_calc(domain) - comodel._apply_ir_rules(query, 'read') - query.order = comodel._order_to_sql(comodel._order, query) - - wquery = comodel._where_calc(domain) - comodel._apply_ir_rules(wquery, 'read') - sql_id1 = SQL.identifier(self.relation, self.column1) - sql_id2 = SQL.identifier(self.relation, self.column2) - query.add_join('JOIN', self.relation, None, SQL( - "%s = %s", sql_id2, SQL.identifier(comodel._table, 'id'), - )) - query.add_where(SQL("%s IN %s", sql_id1, tuple(records.ids))) - - group = defaultdict(list) - records.env.execute_query(query.select(sql_id1, sql_id2)) - # for id1, id2 in records.env.execute_query(query.select(sql_id1, sql_id2)): - # group[id1].append(id2) - - for record in records: - if self.name == 'ks_list_view_fields': - field = 'ks_list_view_fields' - elif self.name == 'ks_chart_measure_field': - field = 'ks_chart_measure_field' - elif self.name == 'ks_chart_measure_field_2': - field = 'ks_chart_measure_field_2' - else: - field = 'ks_list_view_group_fields' - order = False - if record.ks_many2many_field_ordering: - order = json.loads(record.ks_many2many_field_ordering).get(field, False) - - - rec_list = records._cr.fetchall() - if order: - for row in order: - group[record.id].append(row) - - else: - for id1, id2 in rec_list: - group[id1].append(id2) - - # store result in cache - # cache = records.env.cache - if order: - try: - group[record.id].sort(key=lambda x: order.index(x)) - except Exception as e: - pass - values = [tuple(group[id_]) for id_ in records._ids] - records.env.cache.insert_missing(records, self, values) - - - else: - context = {'active_test': False} - context.update(self.context) - comodel = records.env[self.comodel_name].with_context(**context) - - # make the query for the lines - domain = self.get_domain_list(records) - query = comodel._where_calc(domain) - comodel._apply_ir_rules(query, 'read') - query.order = comodel._order_to_sql(comodel._order, query) - - # join with many2many relation table - sql_id1 = SQL.identifier(self.relation, self.column1) - sql_id2 = SQL.identifier(self.relation, self.column2) - query.add_join('JOIN', self.relation, None, SQL( - "%s = %s", sql_id2, SQL.identifier(comodel._table, 'id'), - )) - query.add_where(SQL("%s IN %s", sql_id1, tuple(records.ids))) - - # retrieve pairs (record, line) and group by record - group = defaultdict(list) - for id1, id2 in records.env.execute_query(query.select(sql_id1, sql_id2)): - group[id1].append(id2) - - # store result in cache - values = [tuple(group[id_]) for id_ in records._ids] - records.env.cache.insert_missing(records, self, values) - - - -fields.Many2many.read = ks_read - -read_group = models.BaseModel._read_group_groupby - - -def ks_time_addition(self, gb, query): - """ - Overwriting default to add minutes to Helper method to collect important - information about groupbys: raw field name, type, time information, qualified name, ... - """ - split = gb.split(':') - field_type = self._fields[split[0]].type - gb_function = split[1] if len(split) == 2 else None - if gb_function == 'month_year': - gb_function = 'month' - temporal = field_type in ('date', 'datetime') - tz_convert = field_type == 'datetime' and self._context.get('tz') in pytz.all_timezones - qualified_field = self._inherits_join_calc(self._table, split[0], query) - if temporal: - lang = self.env['res.lang']._lang_get(self.env.user.lang).time_format - if '%H' in lang: - display_formats = { - 'minute': 'HH:mm dd MMM', - 'hour': 'HH:00 dd MMM', - 'day': 'dd MMM yyyy', # yyyy = normal year - 'week': "'W'w YYYY", # w YYYY = ISO week-year - 'month': 'MMMM yyyy', - 'quarter': 'QQQ yyyy', - 'year': 'yyyy', - } - else: - display_formats = { - 'minute': 'hh:mm dd MMM', - 'hour': 'hh:00 dd MMM', - 'day': 'dd MMM yyyy', # yyyy = normal year - 'week': "'W'w YYYY", # w YYYY = ISO week-year - 'month': 'MMMM yyyy', - 'quarter': 'QQQ yyyy', - 'year': 'yyyy', - } - time_intervals = { - 'minute': dateutil.relativedelta.relativedelta(minutes=1), - 'hour': dateutil.relativedelta.relativedelta(hours=1), - 'day': dateutil.relativedelta.relativedelta(days=1), - 'week': dt.timedelta(days=7), - 'month': dateutil.relativedelta.relativedelta(months=1), - 'quarter': dateutil.relativedelta.relativedelta(months=3), - 'year': dateutil.relativedelta.relativedelta(years=1) - } - if tz_convert: - qualified_field = "timezone('%s', timezone('UTC',%s))" % (self._context.get('tz', 'UTC'), qualified_field) - qualified_field = "date_trunc('%s', %s::timestamp)" % (gb_function or 'month', qualified_field) - if field_type == 'boolean': - qualified_field = "coalesce(%s,false)" % qualified_field - return { - 'field': split[0], - 'groupby': gb, - 'type': field_type, - 'display_format': display_formats[gb_function or 'month'] if temporal else None, - 'interval': time_intervals[gb_function or 'month'] if temporal else None, - 'tz_convert': tz_convert, - 'qualified_field': qualified_field, - 'granularity': gb_function or 'month' if temporal else None, - } - - -# models.BaseModel._read_group = ks_time_addition - - -class KsDashboardNinjaItems(models.Model): - _name = 'ks_dashboard_ninja.item' - _description = 'Dashboard Ninja items' - - name = fields.Char(string="Name", translate=True, help="The item will be represented by this unique name.") - 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','_%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. ") - ks_dashboard_board_template_id = fields.Many2one('ks_dashboard_ninja.board_template', string="Dashboard Template") - ks_domain = fields.Char(string="Domain", help="Define conditions for filter. ") - - ks_model_id_2 = fields.Many2one('ir.model', string='Kpi Model', - domain="[('access_ids','!=',False),('transient','=',False)," - "('model','not ilike','base_import%'),('model','not 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%')]") - - ks_model_name_2 = fields.Char(related='ks_model_id_2.model', string="Kpi Model Name") - - zoom_enabled = fields.Boolean(string="Zoom enabled?", compute="compute_zoom_enabled") - - def compute_zoom_enabled(self): - for rec in self: - rec.zoom_enabled = self.env['ir.config_parameter'].sudo().get_param('ks_dashboard_ninja.enable_chart_zoom') - - # This field main purpose is to store %UID as current user id. Mainly used in JS file as container. - ks_domain_temp = fields.Char(string="Domain Substitute") - grid_corners = fields.Char(string="grid corners") - ks_background_color = fields.Char(string="Background Color", - default="#DAEAF6,0.99", help=' Select the background color with transparency. ') - ks_icon = fields.Binary(string="Upload Icon", attachment=True) - ks_default_icon = fields.Char(string="Icon", default="bar-chart", help='Select the icon to be displayed. ') - ks_default_icon_color = fields.Char(default="#6789C6,0.99", string="Icon Color", - help='Select the icon to be displayed. ') - ks_icon_select = fields.Selection([("Default","Default"),("Custom","Custom"),],string="Icon Option", default=("Default"), help='Choose the Icon option. ') - ks_font_color = fields.Char(default="#000000,0.99", string="Font Color", help='Select the font color. ') - ks_dashboard_item_theme = fields.Char(string="Theme", default="white", - help='Select the color theme for the display. ') - ks_layout = fields.Selection([('layout1', 'Layout 1'), - ('layout2', 'Layout 2'), - ('layout3', 'Layout 3'), - ('layout4', 'Layout 4'), - ('layout5', 'Layout 5'), - ('layout6', 'Layout 6'), - ], default=('layout5'), required=True, string="Layout", - help=' Select the layout to display records. ') - ks_preview = fields.Integer(default=1, string="Preview") - ks_model_name = fields.Char(related='ks_model_id.model', string="Model Name") - - ks_record_count_type_2 = fields.Selection([('count', 'Count'), - ('sum', 'Sum'), - ('average', 'Average')], string="Kpi Record Type", default="sum") - ks_record_field_2 = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id_2),('name','!=','id'),('name','!=','sequence'),('store','=',True)," - "'|','|',('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Kpi Record Field") - ks_record_count_2 = fields.Float(string="KPI Record Count", readonly=True, compute='ks_get_record_count_2', - compute_sudo=False) - ks_record_count_type = fields.Selection([('count', 'Count'), - ('sum', 'Sum'), - ('average', 'Average')], string="Record Type", default="count", - help="Type of record how record will show as count,sum and average of the record") - ks_record_count = fields.Float(string="Record Count", compute='ks_get_record_count', readonly=True, - compute_sudo=False) - ks_record_field = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('store','=',True),'|'," - "'|',('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Record Field") - ks_send_mail = fields.Boolean(string="Send Mail") - ks_email_to_ids = fields.Many2many('ks_dashboard_ninja.kpi_mail',string="Email Address") - ks_stop_mail_cron = fields.Boolean(string="Stop mail cron") - ks_record_data_limit_visibility = fields.Boolean(string="Record Limit Data Visibility", - help="To enable the record data limit field") - - # Date Filter Fields - # Condition to tell if date filter is applied or not - ks_isDateFilterApplied = fields.Boolean(default=False) - - # ---------------------------- Date Filter Fields ------------------------------------------ - ks_date_filter_selection = fields.Selection([ - ('l_none', 'None'), - ('l_day', 'Today'), - ('t_week', 'This Week'), - ('t_month', 'This Month'), - ('t_quarter', 'This Quarter'), - ('t_year', 'This Year'), - ('td_week', 'Week to Date'), - ('td_month', 'Month to Date'), - ('td_quarter', 'Quarter to Date'), - ('td_year', 'Year to Date'), - ('n_day', 'Next Day'), - ('n_week', 'Next Week'), - ('n_month', 'Next Month'), - ('n_quarter', 'Next Quarter'), - ('n_year', 'Next Year'), - ('ls_day', 'Last Day'), - ('ls_week', 'Last Week'), - ('ls_month', 'Last Month'), - ('ls_quarter', 'Last Quarter'), - ('ls_year', 'Last Year'), - ('l_week', 'Last 7 days'), - ('l_month', 'Last 30 days'), - ('l_quarter', 'Last 90 days'), - ('l_year', 'Last 365 days'), - ('ls_past_until_now', 'Past Till Now'), - ('ls_pastwithout_now', ' Past Excluding Today'), - ('n_future_starting_now', 'Future Starting Now'), - ('n_futurestarting_tomorrow', 'Future Starting Tomorrow'), - ('l_custom', 'Custom Filter'), - ], string="Date Filter Selection", default="l_none", required=True, - help='Select interval of the records to be displayed. ') - ks_date_filter_field = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('store','=',True),'|',('ttype','=','date')," - "('ttype','=','datetime')]", - string="Date Filter Field", - help='Select the field for which Date Filter should be applicable.') - - ks_item_start_date = fields.Datetime(string="Start Date") - ks_item_end_date = fields.Datetime(string="End Date") - - ks_date_filter_field_2 = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id_2),('store','=',True),'|',('ttype','=','date')," - "('ttype','=','datetime')]", - string="Kpi Date Filter Field") - - ks_item_start_date_2 = fields.Datetime(string="Kpi Start Date") - ks_item_end_date_2 = fields.Datetime(string="Kpi End Date") - - ks_domain_2 = fields.Char(string="Kpi Domain") - ks_domain_2_temp = fields.Char(string="Kpi Domain Substitute") - - ks_date_filter_selection_2 = fields.Selection([ - ('l_none', "None"), - ('l_day', 'Today'), - ('t_week', 'This Week'), - ('t_month', 'This Month'), - ('t_quarter', 'This Quarter'), - ('t_year', 'This Year'), - ('td_week', 'Week to Date'), - ('td_month', 'Month to Date'), - ('td_quarter', 'Quarter to Date'), - ('td_year', 'Year to Date'), - ('n_day', 'Next Day'), - ('n_week', 'Next Week'), - ('n_month', 'Next Month'), - ('n_quarter', 'Next Quarter'), - ('n_year', 'Next Year'), - ('ls_day', 'Last Day'), - ('ls_week', 'Last Week'), - ('ls_month', 'Last Month'), - ('ls_quarter', 'Last Quarter'), - ('ls_year', 'Last Year'), - ('l_week', 'Last 7 days'), - ('l_month', 'Last 30 days'), - ('l_quarter', 'Last 90 days'), - ('l_year', 'Last 365 days'), - ('ls_past_until_now', 'Past Till Now'), - ('ls_pastwithout_now', ' Past Excluding Today'), - ('n_future_starting_now', 'Future Starting Now'), - ('n_futurestarting_tomorrow', 'Future Starting Tomorrow'), - ('l_custom', 'Custom Filter'), - ], string="Kpi Date Filter Selection", required=True, default='l_none') - - ks_previous_period = fields.Boolean(string=" Compare With Previous Period ", help='Checkbox to show comparison between the data of present day and the previous selected period. ') - - # ------------------------ Pro Fields -------------------- - ks_dashboard_ninja_board_id = fields.Many2one('ks_dashboard_ninja.board', string="Dashboard", - default=lambda self: self._context[ - 'ks_dashboard_id'] if 'ks_dashboard_id' in self._context - else False) - - # Chart related fields - ks_dashboard_item_type = fields.Selection([('ks_tile', 'Tile'), - ('ks_bar_chart', 'Bar Chart'), - ('ks_horizontalBar_chart', 'Horizontal Bar Chart'), - ('ks_line_chart', 'Line Chart'), - ('ks_area_chart', 'Area Chart'), - ('ks_pie_chart', 'Pie Chart'), - ('ks_doughnut_chart', 'Doughnut Chart'), - ('ks_polarArea_chart', 'Polar Area Chart'), - ('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_kpi', 'KPI'), - ('ks_to_do', 'To Do'), - ('ks_map_view', 'Map View'), - ('ks_funnel_chart', 'Funnel Chart'), - ('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) - ks_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')]", - string="Group By", help=' Define the x-axis of the graph. ') - ks_chart_relation_sub_groupby = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),('ttype','!=','binary')," - "('ttype','!=','many2many'), ('ttype','!=','one2many')]", - string=" Sub Group By", - help='Select the second level of grouping. ') - ks_chart_date_groupby = fields.Selection([('minute', 'Minute'), - ('hour', 'Hour'), - ('day', 'Day'), - ('week', 'Week'), - ('month', 'Month'), - ('quarter', 'Quarter'), - ('year', 'Year'), - ('month_year', 'Month-Year') - ], string="Dashboard Item Chart Group By Type") - ks_chart_date_sub_groupby = fields.Selection([('minute', 'Minute'), - ('hour', 'Hour'), - ('day', 'Day'), - ('week', 'Week'), - ('month', 'Month'), - ('quarter', 'Quarter'), - ('year', 'Year'), - ], string="Dashboard Item Chart Sub Group By Type") - ks_graph_preview = fields.Char(string="Graph Preview", default="Graph Preview") - ks_chart_data = fields.Char(string="Chart Data in string form", compute='ks_get_chart_data', compute_sudo=False) - ks_chart_data_count_type = fields.Selection([('count', 'Count'), ('sum', 'Sum'), ('average', 'Average')], - string="Data Type", default="sum") - ks_chart_measure_field = fields.Many2many('ir.model.fields', 'ks_dn_measure_field_rel', 'measure_field_id', - 'field_id', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Measure 1", help='Data points to be selected.') - ks_chart_is_cumulative = fields.Boolean('Is Cumulative') - ks_chart_cumulative_field = fields.Many2many('ir.model.fields', 'ks_dn_cumulative_measure_field_rel', - 'measure_cumulative_field_id', - 'cumulative_field_id', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name'," - "'!=','sequence'), " - "('store','=',True),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Cumulative Fields", help='Data points to be selected.') - - ks_chart_cumulative = fields.Boolean("Cumulative As Line") - ks_chart_measure_field_2 = fields.Many2many('ir.model.fields', 'ks_dn_measure_field_rel_2', 'measure_field_id_2', - 'field_id', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Line Measure", - help='Data Points displayed with a line in the graph. ') - - ks_bar_chart_stacked = fields.Boolean(string="Stacked Bar Chart", help='Stack the columns of the same record. ') - - ks_semi_circle_chart = fields.Boolean(string="Semi Circle Chart") - - ks_sort_by_field = fields.Many2one('ir.model.fields', - domain="[('model_id', '=', ks_model_id), ('name', '!=', 'id'), ('name', '!=', 'sequence'), ('store', '=', True), " - "('ttype', 'not in', ['one2many', 'binary', 'char', 'text', 'boolean', 'html'])]", - string="Sort By Field", help='Select the desired sorting preference. ') - ks_sort_by_order = fields.Selection([('ASC', 'Ascending'), ('DESC', 'Descending')], - string="Sort Order", help=' Select the order of the sorting. ') - ks_record_data_limit = fields.Integer(string="Record Limit", help=' Records to be displayed on the graph') - - ks_list_view_preview = fields.Char(string="List View Preview", default="List View Preview") - - ks_kpi_preview = fields.Char(string="Kpi Preview", default="KPI Preview") - - ks_kpi_type = fields.Selection([ - ('layout_1', 'KPI With Target'), - ('layout_2', 'Data Comparison'), - ], string="Kpi Layout", default="layout_1") - - ks_target_view = fields.Selection([("Number","Number"),("Progress Bar","Progress Bar"),],string="View", default="Number", help=' Select the view to compare target with data.') - - ks_data_comparison = fields.Selection([("None","None"),("Sum","Sum"),("Ratio","Ratio"),("Percentage","Percentage"),],string="Kpi Data Type", default="None") - - ks_kpi_data = fields.Char(string="KPI Data", compute="ks_get_kpi_data", compute_sudo=False) - - ks_chart_item_color = fields.Selection( - [('default', 'Default'), ('dark', 'Dark'), ('material', 'Material'), ('moonrise', 'Moonrise')], - string="Chart Color Palette", default="default", help='Select the display preference. ') - - # ------------------------ List View Fields ------------------------------ - - ks_list_view_type = fields.Selection([('ungrouped', 'Un-Grouped'), ('grouped', 'Grouped')], default="ungrouped", - string="List View Type", required=True, - help='Select the desired list view type. ') - ks_list_view_fields = fields.Many2many('ir.model.fields', 'ks_dn_list_field_rel', 'list_field_id', 'field_id', - domain="[('model_id','=',ks_model_id),('ttype','!=','one2many')," - "('ttype','!=','many2many'),('ttype','!=','binary')]", - string="Fields to show in list", - help=' Select the fields you want to display in the list. ') - - ks_export_all_records = fields.Boolean(string="Export All Records", default=True, - help="when click on boolean button, all the records will be downloaded which are present in entire list") - - ks_list_view_group_fields = fields.Many2many('ir.model.fields', 'ks_dn_list_group_field_rel', 'list_field_id', - 'field_id', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="List View Grouped Fields") - - ks_list_view_data = fields.Char(string="List View Data in JSon", compute='ks_get_list_view_data', - compute_sudo=False) - - # -------------------- Multi Company Feature --------------------- - ks_company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id, - help='Name of the company for which analytics will be displayed in the dashboard. ') - - # -------------------- Target Company Feature --------------------- - ks_goal_enable = fields.Boolean(string="Enable Target", help='Show the set target.') - ks_goal_bar_line = fields.Boolean(string="Show Target As Line") - ks_standard_goal_value = fields.Float(string="Standard Target", help='Show the set target') - ks_goal_lines = fields.One2many('ks_dashboard_ninja.item_goal', 'ks_dashboard_item', string="Target Lines") - - ks_list_target_deviation_field = fields.Many2one('ir.model.fields', 'list_field_id', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - ) - - ks_many2many_field_ordering = fields.Char() - - # TODO : Merge all these fields into one and show a widget to get output for these fields from JS - ks_show_data_value = fields.Boolean(string="Show Data Value", help=' Display value on the graph. . ') - - ks_action_lines = fields.One2many('ks_dashboard_ninja.item_action', 'ks_dashboard_item_id', string="Action Lines") - - ks_actions = fields.Many2one('ir.actions.act_window', domain="[('res_model','=',ks_model_name)]", - string="Actions", help="Redirects you to the selected view. ") - - ks_compare_period = fields.Integer(string="Include Period", - help=' Provide the number of Date Filter Selection you want to include while displaying the record.') - ks_year_period = fields.Integer(string="Same Period Previous Years", - help=' Display the record for the same Date field for the last year. ') - ks_compare_period_2 = fields.Integer(string="KPI Include Period") - ks_year_period_2 = fields.Integer(string="KPI Same Period Previous Years") - - ks_multiplier_active = fields.Boolean(string="Apply Multiplier", default=False, - help="Provides the visibility of multiplier field") - ks_multiplier = fields.Float(string="Multiplier",default=1, help="Provides the multiplication of record value") - - - - # User can select custom units for measure - ks_currency_id= fields.Many2one("res.currency",string="Currency", domain="['|', ('active', '=', False), ('active', '=', True)]", - default=lambda self: self.env.company.currency_id) - - ks_unit = fields.Boolean(string="Show Custom Unit", default=False, help='Display the unit of the data.') - ks_unit_selection = fields.Selection([ - ('monetary', 'Monetary'), - ('custom', 'Custom'), - ], string="Select Unit Type", help='Select the unit to be assigned to the value. ') - ks_chart_unit = fields.Char(string="Enter Unit", size=5, default="", - help="Maximum limit 5 characters, for ex: km, m") - - # User can stop propagation of the tile item - ks_show_records = fields.Boolean(string="Show Records", default=True, help="""This field Enable the click on - Dashboard Items to view the Odoo - default view of records""") - # Field for fill temp data - ks_fill_temporal = fields.Boolean('Fill Temporal Value') - # Domain Extension field - 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=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", - help='Select the type of calculation you want to perform on the data.') - - # to show the Global / Indian / Exact Number Format - ks_data_format = fields.Selection([ - ('global', 'English Format'), - ('indian', 'Indian Format'), - ('colombian', 'Colombian Peso Format'), - ('exact', 'Exact Value')], - string='Number System', - default='global', - help="To Change the number format showing in chart to given option") - ks_button_color = fields.Char(string="Top Button Color", - default="#000000,0.99") - - - ks_is_client_action = fields.Boolean('Client Action', default=False) - ks_client_action = fields.Many2one('ir.actions.client', - string="Client Item Action", - domain="[('name','!=','App Store'),('name','!=','Updates'),('res_model','not ilike','ks_dashboard_ninja.%'),('name','!=','Discuss')]", - help="This Action will be Performed at the end of Drill Down Action") - ks_pagination_limit = fields.Integer('Pagination Limit', default=15) - - ks_multiplier_lines = fields.One2many('ks_dashboard_item.multiplier', 'ks_dashboard_item_id', - - readonly=False, store=True, - string="Multiplier Lines") - - ks_precision_digits = fields.Integer('Digits', compute="_ks_compute_precision_digits", store=True, readonly=False) - - ks_scatter_measure_x_id = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Measure X") - # ks_scatter_ungroup_measure_y_id = fields.Many2one('ir.model.fields', - # domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - # "('store','=',True),'|','|'," - # "('ttype','=','integer'),('ttype','=','float')," - # "('ttype','=','monetary')]", - # string="Measure Y") - 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),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Measure Y") - ks_scatter_field_id = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),('ttype','!=','binary')," - "('ttype','!=','many2many'), ('ttype','!=','one2many')]", - string="Scatter Points") - - ks_data_label_type = fields.Selection([('percent', 'Percent'), ('value', 'Value')], string='Show Data Value Type', - help='When "Show Data Value Type" selected this field enables to select label type in percent or value', - default='percent') - 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_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") - ks_country_code = fields.Char(related="ks_country_id.code", store=True) - ks_bounds = fields.Char(compute="_compute_bounds", store=True) - - ks_funnel_preview = fields.Char(string="Funnel Preview", default="Funnel Preview") - ks_funnel_record_field = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('store','=',True),'|'," - "'|',('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Funnel Record Field") - ks_map_record_field = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('store','=',True),'|'," - "'|',('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Map Record Field") - - 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") - - - 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="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') - model_bool = fields.Boolean(string='Model Bool') - csv_bool = fields.Boolean(string='CSV Bool') - ks_is_external_db = fields.Boolean() - ks_host = fields.Char() - ks_port = fields.Char() - ks_db_name = fields.Char() - ks_db_password = fields.Char() - ks_db_user = fields.Char() - data_source = fields.Selection( - [('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: - result= [] - for item in data: - ks_measure_field_ids = [] - value = {} - chart_switch = { - 'bar': "ks_bar_chart", - 'pie': 'ks_pie_chart', - 'donut': 'ks_doughnut_chart', - 'area': 'ks_area_chart', - 'line': 'ks_line_chart', - 'polar': 'ks_polarArea_chart', - 'horizontalbar': 'ks_horizontalBar_chart', - 'table': "ks_list_view" - } - if item["chart_type"].lower() in ['bar', 'line', 'pie', 'area', 'donut', 'polar', 'horizontalbar']: - ks_measure_id = self.env['ir.model.fields'].search( - [('name', '=', item["aggregations"][0]["field"]), ('model', '=', model)]) - if ks_measure_id and ks_measure_id['ttype'] in ['integer','float','monetary']: - 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: - value['ks_chart_relation_groupby'] = ks_record_id.id - if ks_record_id['ttype'] == "datetime" or ks_record_id['ttype'] == "date": - value['ks_chart_date_groupby'] = "month" - - value["name"] = item["chart_name"] - - ks_model_id = self.env['ir.model'].search([('model', '=', model)]).id - value['ks_model_id'] = ks_model_id - - if item["aggregations"][0]["type"] == 'avg': - value['ks_chart_data_count_type'] = 'average' - else: - value['ks_chart_data_count_type'] = item["aggregations"][0]["type"] - - value['ks_dashboard_item_type'] = chart_switch.get(item['chart_type'], False) - value['ks_dashboard_ninja_board_id'] = ks_dash_id - if ks_measure_field_ids and ks_record_id and ks_model_id: - try: - ks_result = self.create(value) - result.append(ks_result) - except Exception as e: - result - elif item["chart_type"].lower() == "table": - value["name"] = item["chart_name"] - value['ks_dashboard_ninja_board_id'] = ks_dash_id - value['ks_dashboard_item_type'] = chart_switch.get(item['chart_type'], False) - - ks_model_id = self.env['ir.model'].search([('model', '=', model)]).id - value['ks_model_id'] = ks_model_id - - ks_measure_id = self.env['ir.model.fields'].search( - [('name', '=', item["aggregations"][0]["field"]), ('model', '=', model)]) - if ks_measure_id and ks_measure_id['ttype'] in ['integer','float','monetary']: - ks_measure_field_ids.append(ks_measure_id.id) - value["ks_list_view_group_fields"] = [(6, 0, ks_measure_field_ids)] - # value["ks_list_view_fields"] = [(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: - value['ks_chart_relation_groupby'] = ks_record_id.id - if ks_record_id['ttype'] == "datetime" or ks_record_id['ttype'] == "date": - value['ks_chart_date_groupby'] = "month" - value['ks_list_view_type'] = 'grouped' - if ks_measure_field_ids and ks_record_id and ks_model_id: - try: - ks_result = self.create(value) - result.append(ks_result) - except Exception as e: - result - elif item["chart_type"].lower() == "kpi": - value["name"] = item["chart_name"] - value['ks_dashboard_ninja_board_id'] = ks_dash_id - value['ks_dashboard_item_type'] = "ks_kpi" - - ks_model_id = self.env['ir.model'].search([('model', '=', model)]).id - value['ks_model_id'] = ks_model_id - - ks_measure_id = self.env['ir.model.fields'].search( - [('name', '=', item["aggregations"][0]["field"]), ('model', '=', model)]) - if ks_measure_id: - value["ks_record_field"] = ks_measure_id.id - - if item["aggregations"][0]["type"] == 'avg': - value['ks_record_count_type'] = 'average' - else: - value['ks_record_count_type'] = item["aggregations"][0]["type"] - value['ks_background_color'] = "#DAEAF6,0.99" - value['ks_default_icon_color'] = "#000000,0.99" - value['ks_font_color'] = "#000000,0.99" - value['ks_button_color'] = "#000000,0.99" - - if ks_measure_id and ks_model_id: - try: - ks_result = self.create(value) - result.append(ks_result) - except Exception as e: - result - else: - pass - if len(result): - return "success" - else: - return "Abort" - except: - raise ValidationError(_("Getting invalid response from AI, please try again")) - - - # Making model, csv and excel field invisible on condition. - @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') - def read_csv(self): - if self.ks_csv_field: - if ' ' in self.filename or '_' in self.filename: - try: - fp = tempfile.NamedTemporaryFile(delete=False, suffix=".csv") - fp.write(binascii.a2b_base64(self.ks_csv_field)) - fp.seek(0) - - with open(fp.name, 'r', encoding='utf-8') as csvfile: - csv_reader = csv.reader(csvfile) - fields = [] - values = {} - header_row = next(csv_reader) - - for row in header_row: - fields.append(row) - values[row] = None - del_group_by_field = """delete from ks_dashboard_csv_new;""" - self._cr.execute(del_group_by_field) - self.env['ks.dashboard.csv.new'].search([]) - for rec in fields: - self.env['ks.dashboard.csv.new'].create({ - 'name': rec, - }) - - for line in csv_reader: - for i, field in enumerate(fields): - values[field] = line[i] - - values = {} - for field in fields: - values[field] = None - except: - raise ValidationError(_("Invalid file!")) - else: - raise ValidationError('Please add filename which contain Spaces and Underscore in there name only.') - else: - if self.ks_model_id: - model = self.env['ir.model'].search([('id', '=', self.ks_model_id.id)]) - model.unlink() - if self.ks_csv_group_by_lines: - for rec in self.ks_csv_group_by_lines: - rec.unlink() - - # Reading the Excel file - @api.onchange('upload_excel') - def _read_xls(self): - if self.upload_excel: - if ' ' in self.filename or '_' in self.filename: - try: - fp = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") - fp.write(binascii.a2b_base64(self.upload_excel)) - fp.seek(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(_(str(e))) - - 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]), - }) - value += 1 - break - else: - raise ValidationError('Please add filename which contain Spaces and Underscore in there name only.') - else: - if self.ks_group_by_lines: - for rec in self.ks_group_by_lines: - rec.unlink() - if self.ks_model_id: - model = self.env['ir.model'].search([('id', '=', self.ks_model_id.id)]) - model.unlink() - - # 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({ - 'ks_group_by_lines': [(0, 0, { - 'name': rec.name - })] - }) - - def csv_data_sync(self): - data = self.env['ks.dashboard.csv.new'].search([]) - for rec in data: - self.write({ - 'ks_csv_group_by_lines': [(0, 0, { - 'name': rec.name - })] - }) - - # Creating table in ir model and adding column (fields) in it. - def create_table(self): - records = self.ks_group_by_lines - dict = [] - if records: - for rec in records: - values = {} - if not rec.ttype: - raise ValidationError('Please Enter the type under Column Data Type Tab') - values.update({ - 'name': rec.name.lower().replace(' ', '_'), - 'type': rec.ttype - }) - dict.append(values) - if '_' and '-' in self.filename: - split = self.filename.lower().split('_') - split_value = '' - for res in split: - split_value += res - final_split = split_value.split('-') - elif' ' in self.filename: - final_split = self.filename.lower().split(' ') - elif'_' in self.filename: - final_split = self.filename.lower().split('_') - else: - final_split = self.filename.lower().split('.') - tablemodel = 'x_'+final_split[0]+'_'+self.name_seq - tablename = final_split[0]+' '+self.name_seq - model_creation = self.env['ir.model'].create({ - 'name': tablename, - 'model': tablemodel, - 'order': 'x_name asc, id desc', # valid order - }) - for value in dict: - column_name = value.get('name') - column_type = value.get('type') - if '/' in column_name: - column_name = value.get('name').replace('/', '_') - if ' ' in column_name: - column_name = value.get('name').replace(' ', '_') - if '(' and ')' in column_name: - column_name = value.get('name').replace(')', '').replace('(', '') - if column_name == 'name': - column_name = column_name.replace('name', 'name1') - model_creation.write({ - 'field_id': [(0, 0, { - 'name': 'x_'+column_name, - 'ttype': column_type, - 'field_description': column_name.replace('_', ' ') - })] - }) - self.env['ir.model.access'].sudo().create({ - 'name': model_creation.name + ' all_user', - 'model_id': model_creation.id, - 'perm_read': True, - 'perm_write': False, - 'perm_create': False, - 'perm_unlink': False, - }) - self.ks_model_id = model_creation.id - try: - self.insert_data_into_table(tablemodel) - except Exception as e: - raise ValidationError("Found error while table creation Error {}".format(e)) - - # Inserting data into the ir model table. - def insert_data_into_table(self, tablemodel): - if self.upload_excel: - try: - fp = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") - fp.write(binascii.a2b_base64(self.upload_excel)) - fp.seek(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("Invalid file") - df = df.astype(str) - values ={} - fields = df.columns.tolist() - user_timezone_str = self.env.context.get('tz', 'UTC') - for row_no in range(df.shape[0]): - line = list(df.iloc[row_no]) - val = {} - value = 0 - for field in fields: - if '/' in field: - field = field.replace('/', ' ') - if ' ' in field: - field = field.replace(' ', '_') - if '(' and ')' in field: - field = field.replace(')', '').replace('(', '') - if field == 'Name': - field = field.replace('Name', 'name1') - 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': - user_datetime_str = line[value] - local_datetime = datetime.strptime(user_datetime_str, '%Y-%m-%d %H:%M:%S') - user_timezone = pytz.timezone(user_timezone_str) - localized_datetime = user_timezone.localize(local_datetime) - utc_datetime = localized_datetime.astimezone(pytz.utc) - formatted_utc_datetime = utc_datetime.strftime('%Y-%m-%d %H:%M:%S') - # final_date = pd.to_timedelta(float(line[value]), unit='D') + pd.to_datetime('1899-12-30') - while (value < len(line)): - values.update({ - field: formatted_utc_datetime, - }) - value = value + 1 - break - else: - while (value < len(line)): - values.update({ - field: line[value], - }) - value = value + 1 - break - else: - while (value < len(line)): - values.update({ - field: 'Null', - }) - value = value + 1 - break - else: - while (value < len(line)): - 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': - split = line[value].split(',') - split_value = '' - for res in split: - split_value += res - final_split = split_value.split('.') - final_split_value = '' - for final_res in final_split: - final_split_value += final_res - values.update({ - field: final_split_value, - }) - else: - split = line[value].split(',') - split_value = split[0] + split[1] - final_value = float(split_value) - values.update({ - field: final_value, - }) - elif '@' in line[value]: - values.update({ - field: line[value], - }) - else: - # final_value = (line[value]) - if self.ks_group_by_lines[value].ttype == 'integer' and line[value]!='nan': - try: - values.update({ - field: int(float(line[value])), - }) - except: - values.update({ - field: 0, - }) - 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, - }) - elif line[value] == 'nan': - values.update({ - field: 'Null', - }) - - else: - values.update({ - field: line[value], - }) - elif "'" and '+' in line[value]: - split_value = line[value].split('+') - final_split = '+' + split_value[1] - values.update({ - field: final_split, - }) - elif "'" in line[value]: - split_value = line[value].split("'") - final_split_value = '' - for res in split_value: - final_split_value += res - values.update({ - field: final_split_value, - }) - 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])), - }) - except: - values.update({ - field: 0, - }) - 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, - }) - else: - values.update({ - field: line[value], - }) - value = value + 1 - break - else: - values.update({ - field: 'Null', - }) - value = value + 1 - break - try: - if values.keys(): - data_values = dict([('x_' + key.lower().replace(' ', '_'), values[key]) for key in values if - values[key] != 'Null']) - self.env[tablemodel].sudo().create(data_values) - except Exception as e: - raise ValidationError("Found error while table creation {}".format(e)) - - def csv_create_table(self): - records = self.ks_csv_group_by_lines - dict = [] - if records: - for rec in records: - values = {} - if not rec.ttype: - raise ValidationError('Please Enter the type under Column Data Type Tab') - values.update({ - 'name': rec.name.lower().replace(' ', '_'), - 'type': rec.ttype - }) - dict.append(values) - if '_' and '-' in self.filename: - split = self.filename.lower().split('_') - split_value = '' - for res in split: - split_value += res - final_split = split_value.split('-') - elif ' ' in self.filename: - final_split = self.filename.lower().split(' ') - elif '_' in self.filename: - final_split = self.filename.lower().split('_') - else: - final_split = self.filename.lower().split('.') - tablemodel = 'x_'+final_split[0]+'_'+self.name_seq - tablename = final_split[0]+' '+self.name_seq - model_creation = self.env['ir.model'].create({ - 'name': tablename, - 'model': tablemodel, - 'order': 'x_name asc, id desc', # valid order - }) - for value in dict: - column_name = value.get('name') - column_type = value.get('type') - if '/' in column_name: - column_name = value.get('name').replace('/', '_') - if ' ' in column_name: - column_name = value.get('name').replace(' ', '_') - if '(' and ')' in column_name: - column_name = value.get('name').replace(')', '').replace('(', '') - if column_name == 'name': - column_name = column_name.replace('name', 'name1') - model_creation.write({ - 'field_id': [(0, 0, { - 'name': 'x_'+column_name, - 'ttype': column_type, - 'field_description': column_name.replace('_', ' ') - })] - }) - self.env['ir.model.access'].sudo().create({ - 'name': model_creation.name + ' all_user', - 'model_id': model_creation.id, - 'perm_read': True, - 'perm_write': False, - 'perm_create': False, - 'perm_unlink': False, - }) - self.ks_model_id = model_creation.id - try: - self.insert_data_into_csv_table(tablemodel) - except Exception as e: - raise ValidationError("Found error while table creation Error {}".format(e)) - - - def insert_data_into_csv_table(self, tablemodel): - if self.ks_csv_field: - fp = tempfile.NamedTemporaryFile(delete=False, suffix=".csv") - fp.write(binascii.a2b_base64(self.ks_csv_field)) - fp.seek(0) - - with open(fp.name, 'r', encoding='utf-8') as csvfile: - csv_reader = csv.reader(csvfile) - fields = [] - values = {} - field_values = {} - header_row = next(csv_reader) - user_timezone_str = self.env.context.get('tz', 'UTC') - for row in header_row: - fields.append(row) - field_values[row] = None - for line in csv_reader: - value = 0 - for field in fields: - if ' ' in field: - field = field.replace(' ', '_') - if '/' in field: - field = field.replace('/', ' ') - if '(' and ')' in field: - field = field.replace(')', '').replace('(', '') - if field == 'Name': - field = field.replace('Name', 'name1') - if 'Date' in field or 'Deadline' in field: - if line[value]: - if self.ks_csv_group_by_lines[value].ttype == 'datetime': - user_datetime_str = line[value] - local_datetime = datetime.strptime(user_datetime_str, '%Y-%m-%d %H:%M:%S') - user_timezone = pytz.timezone(user_timezone_str) - localized_datetime = user_timezone.localize(local_datetime) - utc_datetime = localized_datetime.astimezone(pytz.utc) - formatted_utc_datetime = utc_datetime.strftime('%Y-%m-%d %H:%M:%S') - final_date = line[value].split(' ')[0] - while (value < len(line)): - values.update({ - field: formatted_utc_datetime, - }) - value = value + 1 - break - else: - while (value < len(line)): - values.update({ - field: line[value], - }) - value = value + 1 - break - else: - while (value < len(line)): - values.update({ - field: 'Null', - }) - value = value + 1 - break - else: - while (value < len(line)): - if line[value]: - if '$' in line[value]: - line[value] = line[value].replace('$', '') - if '-' in line[value]: - line[value] = line[value].replace('-', '') - if '(' and ')' in line[value]: - line[value] = line[value].replace(')', '').replace('(', '') - if '.' in line[value]: - if ',' in line[value]: - if self.ks_csv_group_by_lines[value].ttype == 'char': - split = line[value].split(',') - split_value = '' - for res in split: - split_value += res - final_split = split_value.split('.') - final_split_value = '' - for final_res in final_split: - final_split_value += final_res - values.update({ - field: final_split_value, - }) - else: - split = line[value].split(',') - split_value = split[0] + split[1] - if self.ks_csv_group_by_lines[value].ttype == 'float': - values.update({ - field: float(split_value), - }) - elif self.ks_csv_group_by_lines[value].ttype == 'integer': - values.update({ - field: int(float(split_value)), - }) - else: - values.update({ - field: split_value, - }) - elif '@' in line[value]: - values.update({ - field: line[value], - }) - else: - if self.ks_csv_group_by_lines[value].ttype == 'float': - 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], - }) - elif "'" and '+' in line[value]: - split_value = line[value].split('+') - final_split = '+' + split_value[1] - values.update({ - field: final_split, - }) - elif "'" in line[value]: - split_value = line[value].split("'") - final_split_value = '' - for res in split_value: - final_split_value += res - values.update({ - field: final_split_value, - }) - elif line[value] == ' ': - values.update({ - field: 'Null', - }) - value = value + 1 - break - elif self.ks_csv_group_by_lines[value].ttype == 'float': - 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], - }) - value = value + 1 - break - else: - values.update({ - field: 'Null', - }) - value = value + 1 - break - try: - if values.keys(): - data_values = dict([('x_' + key.lower().replace(' ', '_'), values[key]) for key in values if - values[key] != 'Null']) - self.env[tablemodel].sudo().create(data_values) - except Exception as e: - raise ValidationError("Found error while table creation Error {}".format(e)) - - def check_target(self): - base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') - sales_target = self.env['ks_dashboard_ninja.item'].search([ - ('ks_dashboard_item_type', '=', 'ks_kpi'), - ('ks_send_mail', '=', True), - ('ks_stop_mail_cron', '=' , False) - ]) - menu_record = self.env.ref('ks_dashboard_ninja.board_menu_root') - menu_id_1 = menu_record.id - recipient_emails = [] - email_from = self.env['res.company'].search([], limit=1) - for res in sales_target: - if res.ks_record_count >= res.ks_standard_goal_value: - dashboard_id = res.ks_dashboard_ninja_board_id.id - action_id = res.ks_dashboard_ninja_board_id.ks_dashboard_menu_id.action.id if res.ks_dashboard_ninja_board_id.ks_dashboard_menu_id.action and res.ks_dashboard_ninja_board_id.ks_dashboard_menu_id.action.id else menu_record.action.id - for partner in res.ks_email_to_ids: - recipient_emails.append(partner.name) - kpi_mail = self.env['mail.mail'].create({ - 'body_html': '

Congratulations! The Target of '+ str(res.ks_standard_goal_value) +' for '+ res.name +' is achieved!!

' - f"

Click here to check the dashboard: " - f"Dashboard Link

", - 'subject' : 'Commendable Achievement: Meeting and Exceeding Sales Targets', - 'email_from' : email_from.email, - 'email_to': ','.join(recipient_emails), - }) - kpi_mail.sudo().send() - res.ks_stop_mail_cron = True - recipient_emails = [] - - def write(self, vals): - if vals.get('ks_standard_goal_value') or vals.get('ks_record_count_type'): - self.ks_stop_mail_cron = False - return super(KsDashboardNinjaItems, self).write(vals) - - - @api.onchange('ks_year_period', 'ks_year_period_2') - def ks_year_neg_val_not_allow(self): - for rec in self: - if rec.ks_year_period < 0 or rec.ks_year_period_2 < 0 : - raise ValidationError(_(" Negative periods are not allowed ")) - - @api.onchange('ks_item_start_date', 'ks_item_end_date') - def ks_item_date_validation(self): - for rec in self: - if rec.ks_item_start_date and rec.ks_item_end_date: - if rec.ks_item_start_date > rec.ks_item_end_date: - raise ValidationError(_('Start date must be less than end date')) - - @api.onchange('ks_item_start_date_2', 'ks_item_end_date_2') - def ks_item_date_validation_2(self): - for rec in self: - if rec.ks_item_start_date_2 and rec.ks_item_end_date_2: - if rec.ks_item_start_date_2 > rec.ks_item_end_date_2: - raise ValidationError(_('Start date must be less than end date')) - - @api.onchange('ks_dashboard_item_type') - def change_data_source_to_odoo(self): - if self.ks_dashboard_item_type == 'ks_scatter_chart': - self.ks_data_calculation_type = 'custom' - - @api.onchange('ks_dashboard_item_type') - def change_data_calculation_type_to_default(self): - if self.ks_dashboard_item_type == 'ks_map_view': - self.data_source = 'odoo' - - @api.depends('ks_dashboard_item_type') - def _ks_compute_precision_digits(self): - for rec in self: - try: - precision_digits = self.sudo().env.ref('ks_dashboard_ninja.ks_dashboard_ninja_precision') - ks_precision_digits = precision_digits.digits - if ks_precision_digits < 0: - ks_precision_digits = 2 - if ks_precision_digits > 100: - ks_precision_digits = 2 - - rec.ks_precision_digits = ks_precision_digits - except Exception as E: - rec.ks_precision_digits = 2 - # default = lambda self: self.sudo().env.ref('ks_dashboard_ninja.ks_dashboard_ninja_precision') - - @api.onchange('ks_multiplier_active', 'ks_chart_measure_field', - 'ks_chart_measure_field_2' ,'ks_list_view_group_fields') - def _ks_compute_multiplier_lines(self): - for rec in self: - rec.ks_multiplier_lines = [(5, 0, 0)] - ks_chart_measure_fields = rec.ks_chart_measure_field - if rec.ks_multiplier_active: - if rec.ks_dashboard_item_type == 'ks_list_view' and rec.ks_list_view_type == 'grouped': - ks_chart_measure_fields = rec.ks_list_view_group_fields - ks_temp_list = [] - ks_chart_measure_id = [] - for ks_chart_measure_field in ks_chart_measure_fields: - ks_dict = { - 'ks_dashboard_item_id': rec.id, - 'ks_multiplier_fields': ks_chart_measure_field.ids[0], - 'ks_multiplier_value': 1 - } - ks_chart_measure_id.append(ks_chart_measure_field.ids[0]) - ks_line = self.env['ks_dashboard_item.multiplier'].create(ks_dict) - ks_temp_list.append(ks_line.id) - - if rec.ks_chart_measure_field_2: - for ks_chart_measure_field in rec.ks_chart_measure_field_2: - if ks_chart_measure_field.ids[0] not in ks_chart_measure_id: - ks_dict = { - 'ks_dashboard_item_id': rec.id, - 'ks_multiplier_fields': ks_chart_measure_field.ids[0], - 'ks_multiplier_value': 1 - } - ks_line = self.env['ks_dashboard_item.multiplier'].create(ks_dict) - ks_temp_list.append(ks_line.id) - # rec.ks_multiplier_lines = [(6, 0, [])] - # rec.ks_multiplier_lines = [(6, 0, ks_temp_list)] - rec.ks_multiplier_lines = [(6, 0, [])] - rec.ks_multiplier_lines = [(6, 0, ks_temp_list)] - - 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: - if rec.ks_list_view_type == 'ungrouped': - rec.ks_multiplier_active = False - - @api.onchange('ks_data_calculation_type') - def _ks_onchange_ks_data_calculation_type(self): - for rec in self: - if rec.ks_data_calculation_type == 'query': - rec.ks_list_view_type = 'ungrouped' - rec.ks_multiplier_active = False - rec.ks_record_field = False - - @api.onchange('ks_goal_lines') - def ks_is_goal_lines(self): - for rec in self: - if rec.ks_goal_enable and rec.ks_goal_lines: - rec.ks_pagination_limit = 0 - elif rec.ks_goal_enable and not rec.ks_goal_lines: - rec.ks_pagination_limit = 15 - - - @api.onchange('ks_goal_enable') - def ks_is_goal_enable(self): - for rec in self: - if not rec.ks_goal_enable : - rec.ks_goal_lines = False - rec.ks_pagination_limit = 15 - elif rec.ks_goal_enable and not rec.ks_goal_lines: - rec.ks_pagination_limit = 15 - - - @api.onchange('ks_pagination_limit') - def ks_on_negativ_limit(self): - for rec in self: - if rec.ks_pagination_limit > 0: - rec.ks_pagination_limit = rec.ks_pagination_limit - elif not rec.ks_goal_lines and rec.ks_pagination_limit <= 0: - raise ValidationError(_("Pagination limit value cannot be Negative or Zero")) - if rec.ks_goal_lines and rec.ks_pagination_limit > 0 or rec.ks_pagination_limit < 0: - raise ValidationError(_("if target lines is selected then cannot be set pagination value")) - - @api.onchange('ks_is_client_action') - def ks_on_change_item_action_to_client(self): - for rec in self: - if rec.ks_is_client_action: - rec.ks_actions = False - - @api.onchange('ks_record_data_limit_visibility') - def ks_on_change_record_data_visibility(self): - for rec in self: - 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: - self.ks_sort_by_field = self.ks_chart_relation_groupby.id - self.ks_sort_by_order = 'ASC' - else: - self.ks_sort_by_field = False - self.ks_sort_by_order = False - - @api.onchange('ks_goal_lines') - def ks_date_target_line(self): - for rec in self: - if rec.ks_chart_date_groupby in ('minute', 'hour') or rec.ks_chart_date_sub_groupby in ('minute', 'hour'): - rec.ks_goal_lines = False - return {'warning': { - 'title': _('Groupby Field aggregation'), - 'message': _( - 'Cannot create target lines when Group By Date field is set to have aggregation in ' - 'Minute and Hour case.') - }} - - @api.onchange('ks_chart_date_groupby', 'ks_chart_date_sub_groupby') - def ks_date_target(self): - for rec in self: - if (rec.ks_chart_date_groupby in ('minute', 'hour') or rec.ks_chart_date_sub_groupby in ('minute', 'hour')) \ - and rec.ks_goal_lines: - raise ValidationError(_( - "Cannot set aggregation having Date time (Hour, Minute) when target lines per date are being used." - " To proceed this, first delete target lines")) - 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( - rec.ks_chart_relation_groupby.display_name, rec.ks_chart_date_groupby)) - if rec.ks_chart_relation_sub_groupby.ttype == 'date' and rec.ks_chart_date_sub_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_sub_groupby)) - - def copy_data(self, default=None): - if default is None: - default = {} - if 'ks_action_lines' not in default: - default['ks_action_lines'] = [(0, 0, line.copy_data()[0]) for line in self.ks_action_lines] - - if 'ks_goal_lines' not in default: - default['ks_goal_lines'] = [(0, 0, line.copy_data()[0]) for line in self.ks_goal_lines] - if 'ks_multiplier_lines' not in default: - default['ks_multiplier_lines'] = [(0, 0, line.copy_data()[0]) for line in self.ks_multiplier_lines] - ks_many2many_field_ordering = self.ks_many2many_field_ordering - ks_list_view_group_fields = [] - ks_list_view_fields = [] - ks_chart_measure_field = [] - ks_chart_measure_field_2 = [] - if ks_many2many_field_ordering: - ks_many2many_field_ordering = json.loads(ks_many2many_field_ordering) - ks_list_view_group_fields = ks_many2many_field_ordering.get('ks_list_view_group_fields', False) - ks_list_view_fields = ks_many2many_field_ordering.get('ks_list_view_fields', False) - ks_chart_measure_field = ks_many2many_field_ordering.get('ks_chart_measure_field', False) - ks_chart_measure_field_2 = ks_many2many_field_ordering.get('ks_chart_measure_field_2', False) - if 'ks_list_view_group_fields' not in default: - default['ks_list_view_group_fields'] = ks_list_view_group_fields - if 'ks_list_view_fields' not in default: - default['ks_list_view_fields'] = ks_list_view_fields - if 'ks_chart_measure_field' not in default: - default['ks_chart_measure_field'] = ks_chart_measure_field - if 'ks_chart_measure_field_2' not in default: - default['ks_chart_measure_field_2'] = ks_chart_measure_field_2 - return super(KsDashboardNinjaItems, self).copy_data(default) - - def copy(self, default=None): - default = default or {} - res = super(KsDashboardNinjaItems, self).copy(default) - - if self.ks_dn_header_lines: - for line in self.ks_dn_header_lines: - ks_line = {} - ks_line['ks_to_do_header'] = line.ks_to_do_header - ks_line['ks_dn_item_id'] = res.id - ks_dn_header_id = self.env['ks_to.do.headers'].create(ks_line) - if line.ks_to_do_description_lines: - for ks_task in line.ks_to_do_description_lines: - ks_task_line = { - 'ks_to_do_header_id': ks_dn_header_id.id, - 'ks_description': ks_task.ks_description, - 'ks_active': ks_task.ks_active - } - - self.env['ks_to.do.description'].create(ks_task_line) - return res - - def name_get(self): - res = [] - for rec in self: - name = rec.name - if not name: - name = rec.ks_model_id.name - res.append((rec.id, name)) - - return res - - @api.model_create_multi - def create(self, values): - """ Override to save list view fields ordering """ - for i in range(len(values)): - # if not values[i].get('ks_model_id', False): - # raise ValidationError(_("Enter or create model ")) - if not values[i].get('ks_many2many_field_ordering', False): - ks_list_view_group_fields_name = [] - ks_list_view_fields_name = [] - ks_chart_measure_field_name = [] - ks_chart_measure_field_2_name = [] - if values[i].get('ks_list_view_group_fields', False) and len(values[i]['ks_list_view_group_fields'][0][2]) > 0: - for measure in values[i]['ks_list_view_group_fields'][0][2]: - ks_measure_id = self.env['ir.model.fields'].search( - [('id', '=', measure)]) - ks_list_view_group_fields_name.append(ks_measure_id.name) - if values[i].get('ks_list_view_fields', False) and len(values[i]['ks_list_view_fields'][0][2]) > 0: - for measure in values[i]['ks_list_view_fields'][0][2]: - ks_measure_id = self.env['ir.model.fields'].search( - [('id', '=', measure)]) - ks_list_view_fields_name.append(ks_measure_id.name) - if values[i].get('ks_chart_measure_field', False) and len(values[i]['ks_chart_measure_field'][0][2]) > 0: - for measure in values[i]['ks_chart_measure_field'][0][2]: - ks_measure_id = self.env['ir.model.fields'].search( - [('id', '=', measure)]) - ks_chart_measure_field_name.append(ks_measure_id.name) - if values[i].get('ks_chart_measure_field_2', False) and len(values[i]['ks_chart_measure_field_2'][0][2]) > 0: - for measure in values[i]['ks_chart_measure_field_2'][0][2]: - ks_measure_id = self.env['ir.model.fields'].search( - [('id', '=', measure)]) - ks_chart_measure_field_2_name.append(ks_measure_id.name) - ks_many2many_field_ordering = { - 'ks_list_view_fields': values[i]['ks_list_view_fields'][0][2] if values[i].get('ks_list_view_fields', False) else [], - 'ks_list_view_fields_name': ks_list_view_fields_name, - 'ks_list_view_group_fields': values[i]['ks_list_view_group_fields'][0][2] if values[i].get('ks_list_view_group_fields', False) else [], - 'ks_list_view_group_fields_name': ks_list_view_group_fields_name , - 'ks_chart_measure_field': values[i]['ks_chart_measure_field'][0][2] if values[i].get('ks_chart_measure_field', False) else [], - 'ks_chart_measure_field_name': ks_chart_measure_field_name, - 'ks_chart_measure_field_2': values[i]['ks_chart_measure_field_2'][0][2] if values[i].get('ks_chart_measure_field_2', False) else [], - 'ks_chart_measure_field_2_name': ks_chart_measure_field_2_name, - } - values[i]['ks_many2many_field_ordering'] = json.dumps(ks_many2many_field_ordering) - seq = self.env['ir.sequence'].next_by_code('ks_dashboard_ninja.item') or 'New' - values[0]['name_seq'] = seq - return super(KsDashboardNinjaItems, self).create( - values) - - @api.onchange('ks_list_view_fields') - def ks_list_view_fields_onchange(self): - ks_many2many_field_ordering = {} - for rec in self: - if rec.ks_many2many_field_ordering: - ks_many2many_field_ordering = json.loads(rec.ks_many2many_field_ordering) - ks_many2many_field_ordering['ks_list_view_fields'] = rec.ks_list_view_fields.ids - ks_many2many_field_ordering['ks_list_view_fields_name'] = [x.name for x in rec.ks_list_view_fields] - - rec.ks_many2many_field_ordering = json.dumps(ks_many2many_field_ordering) - - @api.onchange('ks_list_view_group_fields') - def ks_list_view_group_fields_onchange(self): - ks_many2many_field_ordering = {} - for rec in self: - if rec.ks_many2many_field_ordering: - ks_many2many_field_ordering = json.loads(rec.ks_many2many_field_ordering) - ks_many2many_field_ordering['ks_list_view_group_fields'] = rec.ks_list_view_group_fields.ids - ks_many2many_field_ordering['ks_list_view_group_fields_name'] = [x.name for x in rec.ks_list_view_group_fields] - rec.ks_many2many_field_ordering = json.dumps(ks_many2many_field_ordering) - - @api.onchange('ks_chart_measure_field') - def ks_chart_measure_field_onchange(self): - for rec in self: - ks_many2many_field_ordering = {} - if rec.ks_many2many_field_ordering: - ks_many2many_field_ordering = json.loads(rec.ks_many2many_field_ordering) - ks_many2many_field_ordering['ks_chart_measure_field'] = rec.ks_chart_measure_field.ids - ks_many2many_field_ordering['ks_chart_measure_field_name'] = [x.name for x in - rec.ks_chart_measure_field] - rec.ks_many2many_field_ordering = json.dumps(ks_many2many_field_ordering) - - @api.onchange('ks_chart_measure_field_2') - def ks_chart_measure_field_2_onchange(self): - ks_many2many_field_ordering = {} - for rec in self: - if rec.ks_many2many_field_ordering: - ks_many2many_field_ordering = json.loads(rec.ks_many2many_field_ordering) - ks_many2many_field_ordering['ks_chart_measure_field_2'] = rec.ks_chart_measure_field_2.ids - ks_many2many_field_ordering['ks_chart_measure_field_2_name'] = [x.name for x in - rec.ks_chart_measure_field_2] - rec.ks_many2many_field_ordering = json.dumps(ks_many2many_field_ordering) - - - - @api.onchange('ks_layout','ks_dashboard_item_theme') - def layout_four_font_change(self): - if self.ks_dashboard_item_theme != "white": - if self.ks_layout == 'layout4' and self.ks_dashboard_item_theme in ['red','blue','yellow','green']: - self.ks_font_color = '#E7495E,0.99' - self.ks_default_icon_color = "#6789C6,0.99" - elif self.ks_layout == 'layout4' and self.ks_dashboard_item_theme not in ['red','blue','yellow','green']: - self.ks_font_color = '#000000,0.99' - if self.ks_background_color=="#DAEAF6,0.99": - self.ks_default_icon_color="#000000,0.99" - else: - self.ks_default_icon_color = "#000000,0.99" - elif self.ks_layout != 'layout4' and self.ks_dashboard_item_theme not in ['red', 'blue', 'yellow', 'green']: - self.ks_font_color = "#000000,0.99" - elif self.ks_layout == 'layout6': - self.ks_font_color = "#737791,0.99" - self.ks_default_icon_color = "#737791,0.99" - elif self.ks_layout == 'layout3': - self.ks_font_color = "#6789C6,0.99" - else: - self.ks_default_icon_color = "#6789C6,0.99" - self.ks_font_color = "#000000,0.99" - elif self.ks_dashboard_item_type == 'ks_tile' and self.ks_layout == 'layout6': - self.ks_font_color = "#737791,0.99" - self.ks_default_icon_color = "#737791,0.99" - else: - if self.ks_layout == 'layout4': - self.ks_background_color = "#DAEAF6,0.99" - self.ks_font_color = "#E7495E,0.99" - self.ks_default_icon_color = "#6789C6,0.99" - elif self.ks_layout == 'layout3': - self.ks_font_color = "#6789C6,0.99" - else: - self.ks_background_color = "#DAEAF6,0.99" - self.ks_font_color = "#000000,0.99" - self.ks_default_icon_color = "#6789C6,0.99" - - # To convert color into 10% darker. Percentage amount is hardcoded. Change amt if want to change percentage. - def ks_get_dark_color(self, color, opacity): - num = int(color[1:], 16) - amt = -25 - R = (num >> 16) + amt - R = (255 if R > 255 else 0 if R < 0 else R) * 0x10000 - G = (num >> 8 & 0x00FF) + amt - G = (255 if G > 255 else 0 if G < 0 else G) * 0x100 - B = (num & 0x0000FF) + amt - B = (255 if B > 255 else 0 if B < 0 else B) - return "#" + hex(0x1000000 + R + G + B).split('x')[1][1:] + "," + opacity - - @api.onchange('ks_model_id') - def make_record_field_empty(self): - for rec in self: - rec.ks_record_field = False - rec.ks_domain = False - rec.ks_date_filter_field = False - # To show "created on" by default on date filter field on model select. - if rec.ks_model_id: - datetime_field_list = rec.ks_date_filter_field.search( - [('model_id', '=', rec.ks_model_id.id), '|', ('ttype', '=', 'date'), - ('ttype', '=', 'datetime')]).read(['id', 'name']) - for field in datetime_field_list: - if field['name'] == 'create_date': - rec.ks_date_filter_field = field['id'] - else: - 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 - rec.ks_chart_measure_field_2 = False - rec.ks_chart_relation_sub_groupby = False - rec.ks_chart_relation_groupby = False - rec.ks_chart_date_sub_groupby = False - rec.ks_chart_date_groupby = False - rec.ks_sort_by_field = False - rec.ks_sort_by_order = False - rec.ks_record_data_limit = False - rec.ks_list_view_fields = False - rec.ks_list_view_group_fields = False - rec.ks_action_lines = False - rec.ks_actions = False - rec.ks_domain_extension = False - rec.ks_scatter_measure_x_id = False - rec.ks_scatter_measure_y_id = False - - @api.onchange('ks_record_count', 'ks_layout', 'name', 'ks_model_id', 'ks_domain', 'ks_icon_select', - 'ks_default_icon', 'ks_icon', - 'ks_background_color', 'ks_font_color', 'ks_default_icon_color') - def ks_preview_update(self): - self.ks_preview += 1 - - @api.onchange('ks_dashboard_item_theme') - def change_dashboard_item_theme(self): - if self.ks_dashboard_item_theme == "red": - self.ks_background_color = "#DCFCE7,0.99" - if self.ks_dashboard_item_type == 'ks_tile': - self.ks_default_icon_color = "#6789C6,0.99" - self.ks_font_color = "#000000,0.99" - elif self.ks_layout == 'layout3': - self.ks_font_color = "#6789C6,0.99" - else: - self.ks_default_icon_color = "#000000,0.99" - self.ks_font_color = "#000000,0.99" - self.ks_button_color = "#000000,0.99" - elif self.ks_dashboard_item_theme == "blue": - self.ks_background_color = "#FFF4DE,0.99" - if self.ks_dashboard_item_type == 'ks_tile': - self.ks_default_icon_color = "#6789C6,0.99" - self.ks_font_color = "#000000,0.99" - elif self.ks_layout == 'layout3': - self.ks_font_color = "#6789C6,0.99" - else: - self.ks_default_icon_color = "#000000,0.99" - self.ks_font_color = "#000000,0.99" - self.ks_button_color = "#000000,0.99" - elif self.ks_dashboard_item_theme == "yellow": - self.ks_background_color = "#F3E8FF,0.99" - if self.ks_dashboard_item_type == 'ks_tile': - self.ks_default_icon_color = "#6789C6,0.99" - self.ks_font_color = "##E7495E,0.99" - elif self.ks_layout == 'layout3': - self.ks_font_color = "#6789C6,0.99" - else: - self.ks_default_icon_color = "#000000,0.99" - self.ks_font_color = "#000000,0.99" - self.ks_button_color = "#000000,0.99" - elif self.ks_dashboard_item_theme == "green": - self.ks_background_color = "#FFE2E5,0.99" - if self.ks_dashboard_item_type == 'ks_tile': - self.ks_default_icon_color = "#6789C6,0.99" - self.ks_font_color = "#000000,0.99" - elif self.ks_layout == 'layout3': - self.ks_font_color = "#6789C6,0.99" - else: - self.ks_default_icon_color = "#000000,0.99" - self.ks_font_color = "#000000,0.99" - self.ks_button_color = "#000000,0.99" - elif self.ks_dashboard_item_theme == "white": - if self.ks_layout == 'layout4': - self.ks_background_color = "#DAEAF6,0.99" - self.ks_default_icon_color = "#6789C6,0.99" - self.ks_font_color = "#E7495E,0.99" - self.ks_button_color = "#6789C6,0.99" - elif self.ks_layout == 'layout3': - self.ks_font_color = "#6789C6,0.99" - self.ks_button_color = "#000000,0.99" - else: - self.ks_background_color = "#DAEAF6,0.99" - self.ks_default_icon_color = "#6789C6,0.99" - self.ks_font_color = "#000000,0.99" - self.ks_button_color = "#000000,0.99" - - if self.ks_layout == 'layout4': - self.ks_font_color = "#DAEAF6,0.99" - self.ks_button_color = "#000000,0.99" - - elif self.ks_dashboard_item_type == 'ks_tile' and self.ks_layout == 'layout6': - self.ks_default_icon_color = "#000000,0.99" - if self.ks_dashboard_item_theme == "white": - self.ks_default_icon_color = "#000000,0.99" - - @api.depends('ks_record_count_type', 'ks_model_id', 'ks_domain', 'ks_record_field', 'ks_date_filter_field', - 'ks_item_end_date', 'ks_item_start_date', 'ks_compare_period', 'ks_year_period', - 'ks_dashboard_item_type', 'ks_domain_extension', 'ks_data_format') - def ks_get_record_count(self): - for rec in self: - rec.ks_record_count = rec._ksGetRecordCount(domain=[]) - - def unlink(self): - channel = self.env['discuss.channel'].search([('ks_dashboard_item_id', 'in', self.ids)]) - if channel: - channel.unlink() - return super(KsDashboardNinjaItems, self).unlink() - - def _ksGetRecordCount(self, domain=[]): - rec = self - if rec.ks_record_count_type == 'count' or rec.ks_dashboard_item_type == 'ks_list_view': - ks_record_count = rec.ks_fetch_model_data(rec.ks_model_name, rec.ks_domain, 'search_count', rec, domain) - elif rec.ks_record_count_type in ['sum', - 'average'] and rec.ks_record_field and rec.ks_dashboard_item_type != 'ks_list_view': - ks_records_grouped_data = rec.ks_fetch_model_data(rec.ks_model_name, rec.ks_domain, 'read_group', rec, - domain) - if ks_records_grouped_data and len(ks_records_grouped_data) > 0: - ks_records_grouped_data = ks_records_grouped_data[0] - if rec.ks_record_count_type == 'sum' and ks_records_grouped_data.get('__count', False) and ( - ks_records_grouped_data.get(rec.ks_record_field.name)): - ks_record_count = ks_records_grouped_data.get(rec.ks_record_field.name, 0) - elif rec.ks_record_count_type == 'average' and ks_records_grouped_data.get( - '__count', False) and (ks_records_grouped_data.get(rec.ks_record_field.name)): - ks_record_count = ks_records_grouped_data.get(rec.ks_record_field.name, - 0) / ks_records_grouped_data.get('__count', - 1) - else: - ks_record_count = 0 - else: - ks_record_count = 0 - else: - ks_record_count = 0 - return ks_record_count - - # Writing separate function to fetch dashboard item data - def ks_fetch_model_data(self, ks_model_name, ks_domain, ks_func, rec, domain=[]): - data = 0 - try: - if ks_domain and ks_domain != '[]' and ks_model_name: - proper_domain = self.ks_convert_into_proper_domain(ks_domain, rec, domain) - if ks_func == 'search_count': - data = self.env[ks_model_name].search_count(proper_domain) - elif ks_func == 'read_group': - data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field.name], [], lazy=False) - elif ks_model_name: - # Have to put extra if condition here because on load,model giving False value - proper_domain = self.ks_convert_into_proper_domain(False, rec, domain) - if ks_func == 'search_count': - data = self.env[ks_model_name].search_count(proper_domain) - - elif ks_func == 'read_group': - data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field.name], [], lazy=False) - else: - return [] - except Exception as e: - return 0 - return data - - def ks_convert_into_proper_domain(self, ks_domain, rec, domain=[]): - if ks_domain and "%UID" in ks_domain: - ks_domain = ks_domain.replace('"%UID"', str(self.env.user.id)) - - if ks_domain and "%MYCOMPANY" in ks_domain: - ks_domain = replace_company_domain(ks_domain, self.env.company.id, self.env.companies.ids) - - ks_date_domain = False - if rec.ks_date_filter_field: - if not rec.ks_date_filter_selection or rec.ks_date_filter_selection == "l_none": - selected_start_date = self._context.get('ksDateFilterStartDate', False) - selected_end_date = self._context.get('ksDateFilterEndDate', False) - ks_is_def_custom_filter = self._context.get('ksIsDefultCustomDateFilter', False) - ks_timezone = self._context.get('tz') or self.env.user.tz - if selected_start_date and selected_end_date and rec.ks_date_filter_field.ttype == 'datetime' and not ks_is_def_custom_filter: - selected_start_date = ks_convert_into_utc(selected_start_date, ks_timezone) - selected_end_date = ks_convert_into_utc(selected_end_date, ks_timezone) - if selected_start_date and selected_end_date and rec.ks_date_filter_field.ttype == 'date' and ks_is_def_custom_filter: - selected_start_date = ks_convert_into_local(selected_start_date, ks_timezone) - selected_end_date = ks_convert_into_local(selected_end_date, ks_timezone) - - if self._context.get('ksDateFilterSelection', False) and self._context['ksDateFilterSelection'] not in [ - 'l_none', 'l_custom']: - ks_date_data = ks_get_date(self._context.get('ksDateFilterSelection'), 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_end_date and not selected_start_date: - ks_date_domain = [ - (rec.ks_date_filter_field.name, "<=", - selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] - elif selected_start_date and not selected_end_date: - ks_date_domain = [ - (rec.ks_date_filter_field.name, ">=", - selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] - else: - if selected_end_date and selected_start_date: - ks_date_domain = [ - (rec.ks_date_filter_field.name, ">=", - selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), - (rec.ks_date_filter_field.name, "<=", - selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] - - else: - if rec.ks_date_filter_selection and rec.ks_date_filter_selection != 'l_custom': - 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"] - else: - selected_start_date = False - selected_end_date = False - if rec.ks_item_start_date or rec.ks_item_end_date: - selected_start_date = rec.ks_item_start_date - selected_end_date = rec.ks_item_end_date - if rec.ks_date_filter_field.ttype == 'date' and rec.ks_item_start_date and rec.ks_item_end_date: - ks_timezone = self._context.get('tz') or self.env.user.tz - selected_start_date = ks_convert_into_local(rec.ks_item_start_date, ks_timezone) - selected_end_date = ks_convert_into_local(rec.ks_item_end_date, ks_timezone) - - if selected_start_date and selected_end_date: - if rec.ks_compare_period: - ks_compare_period = abs(rec.ks_compare_period) - if ks_compare_period > 100: - ks_compare_period = 100 - if rec.ks_compare_period > 0: - selected_end_date = selected_end_date + ( - selected_end_date - selected_start_date) * ks_compare_period - if rec.ks_date_filter_field.ttype == "date" and rec.ks_date_filter_selection == 'l_day': - selected_end_date = selected_end_date + timedelta(days=ks_compare_period) - elif rec.ks_compare_period < 0: - selected_start_date = selected_start_date - ( - selected_end_date - selected_start_date) * ks_compare_period - if rec.ks_date_filter_field.ttype == "date" and rec.ks_date_filter_selection == 'l_day': - selected_start_date = selected_end_date - timedelta(days=ks_compare_period) - - if rec.ks_year_period and rec.ks_year_period != 0 and rec.ks_dashboard_item_type: - abs_year_period = abs(rec.ks_year_period) - sign_yp = rec.ks_year_period / abs_year_period - if abs_year_period > 100: - abs_year_period = 100 - date_field_name = rec.ks_date_filter_field.name - - ks_date_domain = ['&', (date_field_name, ">=", - fields.datetime.strftime(selected_start_date, - DEFAULT_SERVER_DATETIME_FORMAT)), - (date_field_name, "<=", - fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT))] - - for p in range(1, abs_year_period + 1): - ks_date_domain.insert(0, '|') - ks_date_domain.extend(['&', (date_field_name, ">=", fields.datetime.strftime( - selected_start_date - relativedelta.relativedelta(years=p) * sign_yp, - DEFAULT_SERVER_DATETIME_FORMAT)), - (date_field_name, "<=", fields.datetime.strftime( - selected_end_date - relativedelta.relativedelta(years=p) - * sign_yp, DEFAULT_SERVER_DATETIME_FORMAT))]) - else: - selected_start_date = fields.datetime.strftime(selected_start_date, - DEFAULT_SERVER_DATETIME_FORMAT) - selected_end_date = fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT) - ks_date_domain = [(rec.ks_date_filter_field.name, ">=", selected_start_date), - (rec.ks_date_filter_field.name, "<=", selected_end_date)] - elif selected_start_date and not selected_end_date: - selected_start_date = fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT) - ks_date_domain = [(rec.ks_date_filter_field.name, ">=", selected_start_date)] - elif selected_end_date and not selected_start_date: - selected_end_date = fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT) - ks_date_domain = [(rec.ks_date_filter_field.name, "<=", selected_end_date)] - else: - ks_date_domain = [] - - proper_domain = safe_eval(ks_domain) if ks_domain else [] - if ks_date_domain: - proper_domain.extend(ks_date_domain) - if rec.ks_domain_extension: - ks_domain_extension = rec.ks_convert_domain_extension(rec.ks_domain_extension, rec) - proper_domain.extend(ks_domain_extension) - if domain: - proper_domain.extend(domain) - - return proper_domain - - def ks_convert_domain_extension(self, ks_extensiom_domain, rec): - if ks_extensiom_domain and "%UID" in ks_extensiom_domain: - 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 = replace_company_domain(ks_extensiom_domain, self.env.company.id, self.env.companies.ids) - if "%MYCOMPANY" in ks_extensiom_domain: - ks_extensiom_domain = replace_company_domain(ks_extensiom_domain, self.env.company.id, self.env.companies.ids) - - ks_domain = safe_eval(ks_extensiom_domain) - return ks_domain - - @api.onchange('ks_domain_extension') - def ks_onchange_domain_extension(self): - if self.ks_domain_extension: - proper_domain = [] - try: - ks_domain_extension = self.ks_domain_extension - if "%UID" in ks_domain_extension: - ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) - if "%MYCOMPANY" in ks_domain_extension: - ks_domain_extension = replace_company_domain(ks_domain_extension, self.env.company.id, self.env.companies.ids) - self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) - except Exception: - raise ValidationError( - "Domain Extension Syntax is wrong. \nProper Syntax Example :[[','','" - "']]") - - @api.constrains('ks_domain_extension') - def ks_check_domain_extension(self): - if self.ks_domain_extension: - proper_domain = [] - try: - ks_domain_extension = self.ks_domain_extension - if "%UID" in ks_domain_extension: - ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) - if "%MYCOMPANY" in ks_domain_extension: - ks_domain_extension = replace_company_domain(ks_domain_extension, self.env.company.id, self.env.companies.ids) - self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) - except Exception: - raise ValidationError( - "Domain Extension Syntax is wrong. \nProper Syntax Example :[[',''," - "'']]") - - @api.onchange('ks_domain_extension_2') - def ks_onchange_domain_extension_2(self): - if self.ks_domain_extension_2: - proper_domain = [] - try: - ks_domain_extension = self.ks_domain_extension_2 - if "%UID" in ks_domain_extension: - ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) - if "%MYCOMPANY" in ks_domain_extension: - ks_domain_extension = replace_company_domain(ks_domain_extension, self.env.company.id, self.env.companies.ids) - self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) - except Exception: - raise ValidationError( - "Domain Extension Syntax is wrong. \nProper Syntax Example :[[',''," - "'']]") - - @api.constrains('ks_domain_extension_2') - def ks_check_domain_extension_2(self): - if self.ks_domain_extension: - proper_domain = [] - try: - ks_domain_extension = self.ks_domain_extension - if "%UID" in ks_domain_extension: - ks_domain_extension = ks_domain_extension.replace("%UID", str(self.env.user.id)) - if "%MYCOMPANY" in ks_domain_extension: - ks_domain_extension = replace_company_domain(ks_domain_extension, self.env.company.id, self.env.companies.ids) - self.env[self.ks_model_name].search_count(safe_eval(ks_domain_extension)) - except Exception: - raise ValidationError( - "Domain Extension Syntax is wrong. \nProper Syntax Example :[[',''," - "'']]") - - @api.depends('ks_chart_relation_groupby') - def get_chart_groupby_type(self): - for rec in self: - if rec.ks_chart_relation_groupby.ttype == 'datetime' or rec.ks_chart_relation_groupby.ttype == 'date': - rec.ks_chart_groupby_type = 'date_type' - elif rec.ks_chart_relation_groupby.ttype == 'many2one': - rec.ks_chart_groupby_type = 'relational_type' - rec.ks_chart_date_groupby = False - elif rec.ks_chart_relation_groupby.ttype == 'selection': - rec.ks_chart_groupby_type = 'selection' - rec.ks_chart_date_groupby = False - else: - rec.ks_chart_groupby_type = 'other' - - @api.onchange('ks_chart_relation_groupby') - def ks_empty_sub_group_by(self): - for rec in self: - if not rec.ks_chart_relation_groupby or rec.ks_chart_groupby_type == "date_type" \ - and not rec.ks_chart_date_groupby: - rec.ks_chart_relation_sub_groupby = False - rec.ks_chart_date_sub_groupby = False - if not (rec.ks_chart_relation_groupby.ttype == 'datetime' or \ - rec.ks_chart_relation_groupby.ttype == 'date'): - rec.ks_goal_lines = False - rec.ks_goal_enable = False - rec.ks_fill_temporal = False - rec.ks_as_of_now = False - - @api.onchange('ks_chart_relation_sub_groupby', 'ks_fill_temporal','ks_as_of_now', 'ks_goal_lines') - def ks_empty_limit(self): - for rec in self: - if rec.ks_chart_relation_sub_groupby or rec.ks_fill_temporal or rec.ks_goal_lines: - rec.ks_record_data_limit = 0 - if rec.ks_chart_relation_sub_groupby: - rec.ks_chart_cumulative_field = False - rec.ks_fill_temporal = False - rec.ks_as_of_now = False - - @api.depends('ks_chart_relation_sub_groupby') - def get_chart_sub_groupby_type(self): - for rec in self: - if rec.ks_chart_relation_sub_groupby.ttype == 'datetime' or \ - rec.ks_chart_relation_sub_groupby.ttype == 'date': - rec.ks_chart_sub_groupby_type = 'date_type' - elif rec.ks_chart_relation_sub_groupby.ttype == 'many2one': - rec.ks_chart_sub_groupby_type = 'relational_type' - - elif rec.ks_chart_relation_sub_groupby.ttype == 'selection': - rec.ks_chart_sub_groupby_type = 'selection' - - else: - rec.ks_chart_sub_groupby_type = 'other' - - @api.depends('ks_chart_measure_field', 'ks_map_record_field', 'ks_funnel_record_field', 'ks_chart_cumulative_field', 'ks_chart_relation_groupby', - 'ks_chart_date_groupby', 'ks_domain', - 'ks_dashboard_item_type', 'ks_model_id', 'ks_sort_by_field', 'ks_sort_by_order', - 'ks_record_data_limit', 'ks_chart_data_count_type', 'ks_chart_measure_field_2', 'ks_goal_enable', - 'ks_standard_goal_value', 'ks_goal_bar_line', 'ks_chart_relation_sub_groupby', - '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_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_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=[]): - 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 = [] - - 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 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', 'char', 'boolean', 'selection']: - 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) - - 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'}) - - 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 rec.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( - 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]) - - if len(rec.ks_chart_cumulative_field) > len(rec.ks_chart_measure_field): - rec.ks_chart_cumulative_field = rec.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: - - 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_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: - 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 ((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( - 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 = rec.ks_chart_date_groupby - - 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) - - 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: - 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 = [] - if rec.ks_chart_date_groupby == 'month_year': - ks_chart_date_groupby = 'month' - else: - 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) - - 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 = [] - - 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 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) - - 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: - 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 ks_chart_groupby_relation_fields[0] in res: - 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' or rec.ks_chart_sub_groupby_type != 'date_type': - 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]] and 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: - field_value = res.get(ks_chart_groupby_relation_fields[1]) - if isinstance(field_value, tuple): - labels.append(field_value[1]) - else: - labels.append(str(field_value)) - 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] = {serie[0] : domain} - else: - domains[label].update({serie[0]: 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 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, default=str) - else: - return False - - - @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', - 'ks_record_data_limit', 'ks_list_view_fields', 'ks_list_view_type', 'ks_list_view_group_fields', - 'ks_chart_groupby_type', 'ks_chart_date_groupby', 'ks_date_filter_field', 'ks_item_end_date', - 'ks_item_start_date', 'ks_compare_period', 'ks_year_period', 'ks_list_target_deviation_field', - 'ks_goal_enable', 'ks_standard_goal_value', 'ks_goal_lines', 'ks_domain_extension') - def ks_get_list_view_data(self): - for rec in self: - rec.ks_list_view_data = rec._ksGetListViewData(domain=[]) - - def _ksGetListViewData(self, domain=[]): - rec = self - if rec.ks_list_view_type and rec.ks_dashboard_item_type and rec.ks_dashboard_item_type == 'ks_list_view' \ - and rec.ks_model_id: - orderby = rec.ks_sort_by_field.id - sort_order = rec.ks_sort_by_order - ks_chart_domain = self.ks_convert_into_proper_domain(rec.ks_domain, rec, domain) - ks_list_view_data = rec.get_list_view_record(orderby, sort_order, ks_chart_domain) - if ks_list_view_data and len(ks_list_view_data) > 0: - ks_list_view_data = json.dumps(ks_list_view_data) - else: - ks_list_view_data = False - else: - ks_list_view_data = False - return ks_list_view_data - - def get_list_view_record(self, orderid, sort_order, ks_chart_domain, ksoffset=0, - initial_count=0, ks_export_all=False): - ks_list_view_data = {'label': [], 'fields': [], 'fields_type': [], - 'store': [], 'type': self.ks_list_view_type, 'fields_technical_name': [], - 'data_rows': [], 'model': self.ks_model_name} - ks_limit = self.ks_record_data_limit if self.ks_record_data_limit and self.ks_record_data_limit > 0 else False - limit = self.ks_pagination_limit - - if ks_limit: - ks_limit = ks_limit - ksoffset - if ks_limit and ks_limit < self.ks_pagination_limit: - limit = ks_limit - else: - limit = self.ks_pagination_limit - if ks_export_all: - limit = ks_limit - offset = 0 - 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 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: - ks_list_view_data = self.ks_fetch_list_view_data(self, ks_chart_domain, offset=ksoffset, - initial_count=initial_count) - elif self.ks_list_view_type == "grouped" and self.ks_list_view_group_fields \ - and self.ks_chart_relation_groupby: - ks_list_fields = [] - - if self.ks_chart_groupby_type == 'relational_type': - ks_list_view_data['list_view_type'] = 'relational_type' - ks_list_view_data['groupby'] = self.ks_chart_relation_groupby.name - ks_list_fields.append(self.ks_chart_relation_groupby.name) - 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) - ks_list_view_data['fields_technical_name'].append(self.ks_chart_relation_groupby.name) - ks_list_view_data['label'].append(self.ks_chart_relation_groupby.field_description) - for res in self.ks_list_view_group_fields: - ks_list_fields.append(res.name) - ks_list_view_data['label'].append(res.field_description) - ks_list_view_data['fields'].append(res.ids[0]) - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_view_data['fields_technical_name'].append(res.name) - ks_list_view_data['store'].append(res.store) - - try: - ks_list_view_records = self.env[self.ks_model_name]. \ - 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 = [] - for res in ks_list_view_records: - if all(list_fields in res for list_fields in ks_list_fields) \ - and self.ks_chart_relation_groupby.name in res: - counter = 0 - data_row = {'id': res[self.ks_chart_relation_groupby.name] and res[self.ks_chart_relation_groupby.name][0], 'data': [], - 'domain': json.dumps(res['__domain']), 'ks_column_type': []} - for field_rec in ks_list_fields: - if counter == 0: - data_row['data'].append(res[field_rec]) - else: - data_row['data'].append(res[field_rec]) - counter += 1 - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_row) - - elif self.ks_chart_groupby_type == 'date_type' and self.ks_chart_date_groupby: - 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 + ' : ' + ( - '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) - for res in self.ks_list_view_group_fields: - ks_list_fields.append(res.name) - ks_list_field.append(res.name) - ks_list_view_data['label'].append(res.field_description) - ks_list_view_data['fields'].append(res.ids[0]) - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_view_data['store'].append(res.store) - ks_label = ks_list_view_data['label'].copy() - ks_fields = ks_list_view_data['fields'].copy() - ks_fields_type = ks_list_view_data['fields_type'].copy() - - list_target_deviation_field = [] - if self.ks_goal_enable and self.ks_list_target_deviation_field: - list_target_deviation_field.append(self.ks_list_target_deviation_field.name) - if self.ks_list_target_deviation_field.name in ks_list_field: - ks_list_field.remove(self.ks_list_target_deviation_field.name) - ks_list_fields.remove(self.ks_list_target_deviation_field.name) - ks_list_view_data['label'].remove(self.ks_list_target_deviation_field.field_description) - try: - ks_list_view_records = self.env[self.ks_model_name]. \ - read_group(ks_chart_domain, ks_list_field + list_target_deviation_field, - [self.ks_chart_relation_groupby.name + ':' + ks_chart_date_groupby], - orderby=orderby, limit=limit, offset=ksoffset, lazy=False) - except Exception as E: - ks_list_view_records = [] - if all(list_fields in res for res in ks_list_view_records for list_fields in - ks_list_fields + list_target_deviation_field): - for res in ks_list_view_records: - counter = 0 - data_row = {'id': 0, 'data': [], 'domain': json.dumps(res['__domain']), 'ks_column_type': []} - for field_rec in ks_list_fields: - data_row['data'].append(res[field_rec]) - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_row) - - if self.ks_goal_enable: - ks_list_labels = [] - ks_list_view_data['label'].append("Target") - - if self.ks_list_target_deviation_field: - ks_list_view_data['label'].append( - self.ks_list_target_deviation_field.field_description) - ks_list_view_data['label'].append("Achievement") - ks_list_view_data['label'].append("Deviation") - - for res in ks_list_view_records: - ks_list_labels.append(res[ks_list_view_data['groupby']]) - ks_list_view_data2 = self.get_target_list_view_data(ks_list_view_records, self, - ks_list_fields, - ks_list_view_data['groupby'], - list_target_deviation_field, - ks_chart_domain) - ks_list_view_data['data_rows'] = ks_list_view_data2['data_rows'] - ks_list_view_data['store'].clear() - ks_list_view_data['fields_type'].clear() - ks_list_view_data['fields'].clear() - for label in ks_list_view_data['label']: - if label == 'Achievement': - ks_list_view_data['store'].append(False) - ks_list_view_data['fields_type'].append(False) - ks_list_view_data['fields'].append(False) - elif label == 'Target': - ks_list_view_data['store'].append(False) - ks_list_view_data['fields_type'].append(False) - ks_list_view_data['fields'].append(False) - elif label == 'Deviation': - ks_list_view_data['store'].append(False) - ks_list_view_data['fields_type'].append(False) - ks_list_view_data['fields'].append(False) - else: - ks_list_view_data['store'].append(True) - if label in ks_label: - index = ks_label.index(label) - ks_fields_value = ks_fields[index] - ks_fields_type_value = ks_fields_type[index] - ks_list_view_data['fields_type'].append(ks_fields_type_value) - ks_list_view_data['fields'].append(ks_fields_value) - - - - elif self.ks_chart_groupby_type == 'selection': - ks_list_view_data['list_view_type'] = 'selection' - ks_list_view_data['groupby'] = self.ks_chart_relation_groupby.name - 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) - ks_selection_field = self.ks_chart_relation_groupby.name - ks_list_view_data['label'].append(self.ks_chart_relation_groupby.field_description) - ks_list_view_data['fields_technical_name'].append(self.ks_chart_relation_groupby.name) - for res in self.ks_list_view_group_fields: - ks_list_fields.append(res.name) - ks_list_view_data['label'].append(res.field_description) - ks_list_view_data['fields'].append(res.ids[0]) - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_view_data['store'].append(res.store) - ks_list_view_data['fields_technical_name'].append(res.name) - - try: - ks_list_view_records = self.env[self.ks_model_name] \ - .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 = [] - for res in ks_list_view_records: - if all(list_fields in res for list_fields in ks_list_fields): - counter = 0 - data_row = {'id': 0, 'data': [], 'domain': json.dumps(res['__domain']), 'ks_column_type': []} - if res[ks_selection_field]: - data_row['data'].append([res[ks_selection_field], dict( - self.env[self.ks_model_name].fields_get(allfields=ks_selection_field) - [ks_selection_field]['selection'])[res[ks_selection_field]]]) - else: - data_row['data'].append(" ") - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - for field_rec in ks_list_fields: - data_row['data'].append(res[field_rec]) - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_row) - - elif self.ks_chart_groupby_type == 'other': - ks_list_view_data['list_view_type'] = 'other' - ks_list_view_data['groupby'] = self.ks_chart_relation_groupby.name - ks_list_fields.append(self.ks_chart_relation_groupby.name) - 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) - ks_list_view_data['label'].append(self.ks_chart_relation_groupby.field_description) - for res in self.ks_list_view_group_fields: - if res.name != self.ks_chart_relation_groupby.name: - ks_list_fields.append(res.name) - ks_list_view_data['label'].append(res.field_description) - ks_list_view_data['fields'].append(res.ids[0]) - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_view_data['store'].append(res.store) - - try: - ks_list_view_records = self.env[self.ks_model_name] \ - .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 = [] - for res in ks_list_view_records: - if all(list_fields in res for list_fields in ks_list_fields): - counter = 0 - data_row = {'id': 0, 'data': [], 'domain': json.dumps(res['__domain']), 'ks_column_type': []} - - for field_rec in ks_list_fields: - if counter == 0: - data_row['data'].append(res[field_rec]) - else: - if self.ks_chart_relation_groupby.name == field_rec: - data_row['data'].append(res[field_rec] * res[field_rec + '_count']) - else: - data_row['data'].append(res[field_rec]) - counter += 1 - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_row) - - # ks_list_view_data = json.dumps(ks_list_view_data) - if self.ks_multiplier_active and self.ks_list_view_type == 'grouped': - for ks_multiplier in self.ks_multiplier_lines: - label = ks_multiplier.ks_multiplier_fields.field_description - if label in ks_list_view_data['label']: - index = ks_list_view_data['label'].index(label) - for i in range(0, len(ks_list_view_data['data_rows'])): - data_values = ks_list_view_data['data_rows'][i]['data'][index] * ks_multiplier.ks_multiplier_value - ks_list_view_data['data_rows'][i]['data'][index] = data_values - return ks_list_view_data - - def get_target_list_view_data(self, ks_list_view_records, rec, ks_list_fields, ks_group_by, - target_deviation_field, ks_chart_domain): - ks_list_view_data = {} - ks_list_labels = [] - ks_list_records = {} - ks_domains = {} - for res in ks_list_view_records: - ks_list_labels.append(res[ks_group_by]) - ks_domains[res[ks_group_by]] = res['__domain'] - ks_list_records[res[ks_group_by]] = {'measure_field': [], 'deviation_value': 0.0} - ks_list_records[res[ks_group_by]]['measure_field'] = [] - for fields in ks_list_fields[1:]: - ks_list_records[res[ks_group_by]]['measure_field'].append(res[fields]) - for field in target_deviation_field: - ks_list_records[res[ks_group_by]]['deviation'] = res[field] - - 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_2 == "l_none": - selected_start_date = rec._context.get('ksDateFilterStartDate', False) - selected_end_date = rec._context.get('ksDateFilterEndDate', False) - else: - selected_start_date = rec.ks_item_start_date - selected_end_date = rec.ks_item_end_date - - 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.strftime("%Y-%m-%d")), - ('ks_goal_date', '<=', selected_end_date.strftime("%Y-%m-%d"))]) - - ks_date_data = rec.ks_get_start_end_date(rec.ks_model_name, rec.ks_chart_relation_groupby.name, - rec.ks_chart_relation_groupby.ttype, - ks_chart_domain, - ks_goal_domain) - - labels = [] - ks_chart_date_groupby = rec.ks_chart_date_groupby - if rec.ks_chart_date_groupby == 'month_year': - ks_chart_date_groupby = 'month' - 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) - 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 = {} - ks_list_view_data['data_rows'] = [] - 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[res['ks_goal_date' + ":" + ks_chart_date_groupby]] = res['ks_goal_value'] - ks_goal_domains[res['ks_goal_date' + ":" + ks_chart_date_groupby]] = res.get('__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_group_by.split(":")[0] - domain = tuple(domain) - ks_goal_doamins.append(domain) - ks_goal_doamins.insert(0, '&') - ks_goal_domains[goal_domain] = ks_goal_doamins - - ks_chart_records_dates = ks_list_labels + list( - set(ks_goal_labels) - set(ks_list_labels)) - - ks_list_labels_dates = [] - for label in labels: - if label in ks_chart_records_dates: - ks_list_labels_dates.append(label) - - for label in ks_list_labels_dates: - data_rows = {'data': [label], 'ks_column_type': [],'store':True} - data = ks_list_records.get(label, False) - if data: - data_rows['data'] = data_rows['data'] + data['measure_field'] - data_rows['domain'] = json.dumps(ks_domains[label]) - else: - for fields in ks_list_fields[1:]: - data_rows['data'].append(0.0) - data_rows['domain'] = json.dumps(ks_goal_domains[label]) - - target_value = (ks_goal_dataset.get(label, 0.0)) - data_rows['data'].append(target_value) - - for field in target_deviation_field: - ks_multiplier = 1 - if self.ks_multiplier_active: - for line in self.ks_multiplier_lines: - if line.ks_multiplier_fields.name == field: - ks_multiplier = line.ks_multiplier_value - if data: - data_rows['data'].append(data['deviation']) - value = data['deviation'] * ks_multiplier - else: - data_rows['data'].append(0.0) - value = 0 - if target_value: - acheivement = round(((value) / target_value) * 100) - acheivement = str(acheivement) + "%" - else: - acheivement = "" - deviation = (value - target_value) - - data_rows['data'].append(acheivement) - data_rows['data'].append(deviation) - data_rows['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_rows) - - else: - for res in ks_list_view_records: - if all(list_fields in res for list_fields in ks_list_fields): - counter = 0 - data_row = {'id': 0, 'data': [], 'domain': json.dumps(res['__domain']), 'ks_column_type': [],'store':True} - for field_rec in ks_list_fields: - data_row['data'].append(res[field_rec]) - data_row['data'].append(rec.ks_standard_goal_value) - data_row['domain'] = json.dumps(res['__domain']) - for field in target_deviation_field: - ks_multiplier = 1 - if self.ks_multiplier_active: - for line in self.ks_multiplier_lines: - if line.ks_multiplier_fields.name == field: - ks_multiplier = line.ks_multiplier_value - - value = res[field] * ks_multiplier - data_row['data'].append(res[field]) - target_value = rec.ks_standard_goal_value - - if target_value: - acheivement = round(((value) / target_value) * 100) - acheivement = str(acheivement) + "%" - else: - acheivement = "" - - deviation = (value - target_value) - data_row['data'].append(acheivement) - data_row['data'].append(deviation) - ks_list_view_data['data_rows'].append(data_row) - - return ks_list_view_data - - @api.model - def ks_fetch_list_view_data(self, rec, ks_chart_domain, limit=15, offset=0, ks_export_all=False, initial_count=0): - ks_list_view_data = {'label': [], 'fields': [], 'fields_type': [], - 'store': [], 'type': 'ungrouped', - '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 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 - limit = self.ks_pagination_limit - if ks_limit: - ks_limit = ks_limit - offset - if ks_limit and ks_limit < self.ks_pagination_limit: - limit = ks_limit - else: - limit = self.ks_pagination_limit - if ks_export_all: - limit = ks_limit - offset = 0 - if self.ks_list_view_fields: - ks_list_view_data['list_view_type'] = 'other' - ks_list_view_data['groupby'] = False - ks_list_view_data['label'] = [] - ks_list_view_data['date_index'] = [] - ks_list_view_data['fields_technical_name'] = [] - for res in self.ks_list_view_fields: - if (res.ttype == "datetime" or res.ttype == "date"): - index = len(ks_list_view_data['label']) - ks_list_view_data['label'].append(res.field_description) - ks_list_view_data['fields'].append(res.ids[0]) - ks_list_view_data['date_index'].append(index) - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_view_data['store'].append(res.store) - ks_list_view_data['fields_technical_name'].append(res.name) - else: - ks_list_view_data['label'].append(res.field_description) - ks_list_view_data['fields'].append(res.ids[0]) - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_view_data['store'].append(res.store) - ks_list_view_data['fields_technical_name'].append(res.name) - - ks_list_view_fields = [res.name for res in self.ks_list_view_fields] - ks_list_view_field_type = [res.ttype for res in self.ks_list_view_fields] - try: - ks_list_view_records = self.env[self.ks_model_name].search_read(ks_chart_domain, - ks_list_view_fields, - order=orderby, limit=limit, offset=offset) - except Exception as e: - ks_list_view_data = False - return ks_list_view_data - for res in ks_list_view_records: - counter = 0 - data_row = {'id': res['id'], 'data': [], 'ks_column_type': []} - for field_rec in ks_list_view_fields: - if type(res[field_rec]) == fields.datetime: - res[field_rec] = res[field_rec].strftime("%D %T") - elif type(res[field_rec]) == fields.date: - res[field_rec] = res[field_rec].strftime("%D") - elif ks_list_view_field_type[counter] == "many2one": - if res[field_rec]: - res[field_rec] = res[field_rec] - elif ks_list_view_field_type[counter] == "selection" and res.get(field_rec, False): - res[field_rec] = [res[field_rec], dict(self.env[rec.ks_model_name].fields_get(allfields=[field_rec]) - [field_rec]['selection'])[res[field_rec]]] - data_row['data'].append(res[field_rec]) - data_row['ks_column_type'].append(ks_list_view_field_type[counter]) - counter += 1 - ks_list_view_data['data_rows'].append(data_row) - - return ks_list_view_data - - @api.onchange('ks_dashboard_item_type') - def set_color_palette(self): - 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 = "default" - else: - 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": - rec.ks_chart_cumulative_field = False - rec.ks_chart_cumulative = False - rec.ks_multiplier_active = False - rec.ks_model_id_2 = False - rec.ks_chart_measure_field_2 = False - if rec.ks_dashboard_item_type == 'ks_to_do': - rec.ks_model_id_2 = False - rec.ks_model_id = False - - # Time Filter Calculation - - @api.onchange('ks_date_filter_selection') - def ks_set_date_filter(self): - for rec in self: - if (not rec.ks_date_filter_selection) or rec.ks_date_filter_selection == "l_none": - rec.ks_item_start_date = rec.ks_item_end_date = False - elif rec.ks_date_filter_selection != 'l_custom': - ks_date_data = ks_get_date(rec.ks_date_filter_selection, self, rec.ks_date_filter_field.ttype) - rec.ks_item_start_date = ks_date_data["selected_start_date"] - rec.ks_item_end_date = ks_date_data["selected_end_date"] - - @api.depends('ks_dashboard_item_type', 'ks_goal_enable', 'ks_standard_goal_value', 'ks_record_count', - 'ks_record_count_2', 'ks_previous_period', 'ks_compare_period', 'ks_year_period', - 'ks_compare_period_2', 'ks_year_period_2', 'ks_domain_extension_2') - def ks_get_kpi_data(self): - for rec in self: - rec.ks_kpi_data = rec._ksGetKpiData(domain1=[], domain2=[]) - - def _ksGetKpiData(self, domain1=[], domain2=[]): - rec = self - if rec.ks_dashboard_item_type and rec.ks_dashboard_item_type == 'ks_kpi' and rec.ks_model_id: - ks_kpi_data = [] - ks_record_count = 0.0 - ks_kpi_data_model_1 = {} - ks_record_count = rec._ksGetRecordCount(domain1) - ks_kpi_data_model_1['model'] = rec.ks_model_name - ks_kpi_data_model_1['record_field'] = rec.ks_record_field.field_description - ks_kpi_data_model_1['record_data'] = ks_record_count - - if rec.ks_goal_enable: - ks_kpi_data_model_1['target'] = rec.ks_standard_goal_value - ks_kpi_data.append(ks_kpi_data_model_1) - - if rec.ks_previous_period: - ks_previous_period_data = rec.ks_get_previous_period_data(rec) - ks_kpi_data_model_1['previous_period'] = ks_previous_period_data - - if rec.ks_model_id_2 and rec.ks_record_count_type_2: - ks_kpi_data_model_2 = {} - ks_kpi_data_model_2['model'] = rec.ks_model_name_2 - ks_kpi_data_model_2[ - 'record_field'] = 'count' if rec.ks_record_count_type_2 == 'count' else \ - rec.ks_record_field_2.field_description - ks_kpi_data_model_2['record_data'] = rec._ksGetRecordCount_2(domain2) - ks_kpi_data.append(ks_kpi_data_model_2) - - return json.dumps(ks_kpi_data) - else: - return json.dumps([{}]) - - # writing separate function for fetching previous period data - def ks_get_previous_period_data(self, rec): - switcher = { - 'l_day': 'ls_day', - 't_week': 'ls_week', - 't_month': 'ls_month', - 't_quarter': 'ls_quarter', - 't_year': 'ls_year', - } - ks_previous_period = False - ks_date_data = False - if rec.ks_date_filter_selection == "l_none": - date_filter_selection = rec.ks_dashboard_ninja_board_id.ks_date_filter_selection - else: - date_filter_selection = rec.ks_date_filter_selection - ks_previous_period = switcher.get(date_filter_selection, False) - if ks_previous_period: - ks_date_data = ks_get_date(ks_previous_period, self, rec.ks_date_filter_field.ttype) - - if (ks_date_data): - previous_period_start_date = ks_date_data["selected_start_date"] - previous_period_end_date = ks_date_data["selected_end_date"] - proper_domain = rec.ks_get_previous_period_domain(rec.ks_domain, previous_period_start_date, - previous_period_end_date, rec.ks_date_filter_field) - ks_record_count = 0.0 - - if rec.ks_record_count_type == 'count': - ks_record_count = 0 - try: - ks_record_count = self.env[rec.ks_model_name].search_count(proper_domain) - except Exception as E: - ks_record_count = 0 - return ks_record_count - - elif rec.ks_record_field: - try: - data = \ - self.env[rec.ks_model_name].read_group(proper_domain, [rec.ks_record_field.name], [], lazy=False)[0] - except Exception as E: - data = {} - if rec.ks_record_count_type == 'sum': - return data.get(rec.ks_record_field.name, 0) if data.get('__count', False) and ( - data.get(rec.ks_record_field.name)) else 0 - else: - return data.get(rec.ks_record_field.name, 0) / data.get('__count', 1) \ - if data.get('__count', False) and (data.get(rec.ks_record_field.name)) else 0 - else: - return False - else: - return False - - def ks_get_previous_period_domain(self, ks_domain, ks_start_date, ks_end_date, date_filter_field): - if ks_domain and "%UID" in ks_domain: - ks_domain = ks_domain.replace('"%UID"', str(self.env.user.id)) - if ks_domain: - # try: - proper_domain = safe_eval(ks_domain) - if ks_start_date and ks_end_date and date_filter_field: - proper_domain.extend([(date_filter_field.name, ">=", ks_start_date), - (date_filter_field.name, "<=", ks_end_date)]) - - else: - if ks_start_date and ks_end_date and date_filter_field: - proper_domain = ([(date_filter_field.name, ">=", ks_start_date), - (date_filter_field.name, "<=", ks_end_date)]) - else: - proper_domain = [] - return proper_domain - - @api.depends('ks_domain_2', 'ks_model_id_2', 'ks_record_field_2', 'ks_record_count_type_2', 'ks_item_start_date_2', - 'ks_date_filter_selection_2', 'ks_record_count_type_2', 'ks_compare_period_2', 'ks_year_period_2') - def ks_get_record_count_2(self): - for rec in self: - rec.ks_record_count_2 = rec._ksGetRecordCount_2(domain=[]) - - def _ksGetRecordCount_2(self, domain=[]): - rec = self - if rec.ks_record_count_type_2 == 'count': - ks_record_count = rec.ks_fetch_model_data_2(rec.ks_model_name_2, rec.ks_domain_2, 'search_count', rec, - domain) - - elif rec.ks_record_count_type_2 in ['sum', 'average'] and rec.ks_record_field_2: - ks_records_grouped_data = rec.ks_fetch_model_data_2(rec.ks_model_name_2, rec.ks_domain_2, 'read_group', - rec, domain) - if ks_records_grouped_data and len(ks_records_grouped_data) > 0: - ks_records_grouped_data = ks_records_grouped_data[0] - if rec.ks_record_count_type_2 == 'sum' and ks_records_grouped_data.get('__count', False) and ( - ks_records_grouped_data.get(rec.ks_record_field_2.name)): - ks_record_count = ks_records_grouped_data.get(rec.ks_record_field_2.name, 0) - elif rec.ks_record_count_type_2 == 'average' and ks_records_grouped_data.get( - '__count', False) and (ks_records_grouped_data.get(rec.ks_record_field_2.name)): - ks_record_count = ks_records_grouped_data.get(rec.ks_record_field_2.name, - 0) / ks_records_grouped_data.get('__count', - 1) - else: - ks_record_count = 0 - else: - ks_record_count = 0 - else: - ks_record_count = False - - return ks_record_count - - @api.onchange('ks_model_id_2') - def make_record_field_empty_2(self): - for rec in self: - rec.ks_record_field_2 = False - rec.ks_domain_2 = False - rec.ks_date_filter_field_2 = False - rec.ks_previous_period = False - # To show "created on" by default on date filter field on model select. - if rec.ks_model_id: - datetime_field_list = rec.ks_date_filter_field_2.search( - [('model_id', '=', rec.ks_model_id_2.id), '|', ('ttype', '=', 'date'), - ('ttype', '=', 'datetime')]).read(['id', 'name']) - for field in datetime_field_list: - if field['name'] == 'create_date': - rec.ks_date_filter_field_2 = field['id'] - else: - rec.ks_date_filter_field_2 = False - rec.ks_domain_extension_2 = False - - # Writing separate function to fetch dashboard item data - def ks_fetch_model_data_2(self, ks_model_name, ks_domain, ks_func, rec, domain=[]): - data = 0 - try: - if ks_domain and ks_domain != '[]' and ks_model_name: - proper_domain = self.ks_convert_into_proper_domain_2(ks_domain, rec, domain) - if ks_func == 'search_count': - data = self.env[ks_model_name].search_count(proper_domain) - elif ks_func == 'read_group': - data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field_2.name], [], - lazy=False) - elif ks_model_name: - # Have to put extra if condition here because on load,model giving False value - proper_domain = self.ks_convert_into_proper_domain_2(False, rec, domain) - if ks_func == 'search_count': - data = self.env[ks_model_name].search_count(proper_domain) - - elif ks_func == 'read_group': - data = self.env[ks_model_name].read_group(proper_domain, [rec.ks_record_field_2.name], [], - lazy=False) - else: - return [] - except Exception as e: - return [] - return data - - @api.onchange('ks_date_filter_selection_2') - def ks_set_date_filter_2(self): - for rec in self: - if (not rec.ks_date_filter_selection_2) or rec.ks_date_filter_selection_2 == "l_none": - rec.ks_item_start_date_2 = rec.ks_item_end_date = False - elif rec.ks_date_filter_selection_2 != 'l_custom': - ks_date_data = ks_get_date(rec.ks_date_filter_selection_2, self, rec.ks_date_filter_field_2.ttype) - rec.ks_item_start_date_2 = ks_date_data["selected_start_date"] - rec.ks_item_end_date_2 = ks_date_data["selected_end_date"] - - def ks_convert_into_proper_domain_2(self, ks_domain_2, rec, domain=[]): - if ks_domain_2 and "%UID" in ks_domain_2: - ks_domain_2 = ks_domain_2.replace('"%UID"', str(self.env.user.id)) - if ks_domain_2 and "%MYCOMPANY" in ks_domain_2: - ks_domain_2 = replace_company_domain(ks_domain_2, self.env.company.id, self.env.companies.ids) - - ks_date_domain = False - - if rec.ks_date_filter_field_2: - if not rec.ks_date_filter_selection_2 or rec.ks_date_filter_selection_2 == "l_none": - selected_start_date = self._context.get('ksDateFilterStartDate', False) - selected_end_date = self._context.get('ksDateFilterEndDate', False) - ks_is_def_custom_filter = self._context.get('ksIsDefultCustomDateFilter', False) - ks_timezone = self._context.get('tz') or self.env.user.tz - if selected_start_date and selected_end_date and rec.ks_date_filter_field_2.ttype == 'datetime' and not ks_is_def_custom_filter: - selected_start_date = ks_convert_into_utc(selected_start_date, ks_timezone) - selected_end_date = ks_convert_into_utc(selected_end_date, ks_timezone) - if selected_start_date and selected_end_date and rec.ks_date_filter_field_2.ttype == 'date' and ks_is_def_custom_filter: - selected_start_date = ks_convert_into_local(selected_start_date, ks_timezone) - selected_end_date = ks_convert_into_local(selected_end_date, ks_timezone) - if self._context.get('ksDateFilterSelection', False) and self._context['ksDateFilterSelection'] not in [ - 'l_none', 'l_custom']: - ks_date_data = ks_get_date(self._context.get('ksDateFilterSelection'), self, - rec.ks_date_filter_field_2.ttype) - selected_start_date = ks_date_data["selected_start_date"] - selected_end_date = ks_date_data["selected_end_date"] - - if selected_end_date and not selected_start_date: - ks_date_domain = [ - (rec.ks_date_filter_field_2.name, "<=", - selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] - elif selected_start_date and not selected_end_date: - ks_date_domain = [ - (rec.ks_date_filter_field_2.name, ">=", - selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] - else: - if selected_end_date and selected_start_date: - ks_date_domain = [ - (rec.ks_date_filter_field_2.name, ">=", - selected_start_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), - (rec.ks_date_filter_field_2.name, "<=", - selected_end_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT))] - else: - if rec.ks_date_filter_selection_2 and rec.ks_date_filter_selection_2 != 'l_custom': - ks_date_data = ks_get_date(rec.ks_date_filter_selection_2, self, rec.ks_date_filter_field_2.ttype) - selected_start_date = ks_date_data["selected_start_date"] - selected_end_date = ks_date_data["selected_end_date"] - else: - selected_start_date = False - selected_end_date = False - if rec.ks_item_start_date_2 or rec.ks_item_end_date_2: - selected_start_date = rec.ks_item_start_date_2 - selected_end_date = rec.ks_item_end_date_2 - if rec.ks_date_filter_field_2.ttype == 'date' and rec.ks_item_start_date_2 and rec.ks_item_end_date_2: - ks_timezone = self._context.get('tz') or self.env.user.tz - selected_start_date = ks_convert_into_local(rec.ks_item_start_date_2, ks_timezone) - selected_end_date = ks_convert_into_local(rec.ks_item_end_date_2, ks_timezone) - - if selected_start_date and selected_end_date: - if rec.ks_compare_period_2: - ks_compare_period_2 = abs(rec.ks_compare_period_2) - if ks_compare_period_2 > 100: - ks_compare_period_2 = 100 - if rec.ks_compare_period_2 > 0: - selected_end_date = selected_end_date + ( - selected_end_date - selected_start_date) * ks_compare_period_2 - if rec.ks_date_filter_field.ttype == "date" and rec.ks_date_filter_selection == 'l_day': - selected_end_date = selected_end_date + timedelta(days=ks_compare_period_2) - elif rec.ks_compare_period_2 < 0: - selected_start_date = selected_start_date - ( - selected_end_date - selected_start_date) * ks_compare_period_2 - if rec.ks_date_filter_field.ttype == "date" and rec.ks_date_filter_selection == 'l_day': - selected_start_date = selected_end_date - timedelta(days=ks_compare_period_2) - - if rec.ks_year_period_2 and rec.ks_year_period_2 != 0: - abs_year_period_2 = abs(rec.ks_year_period_2) - sign_yp = rec.ks_year_period_2 / abs_year_period_2 - if abs_year_period_2 > 100: - abs_year_period_2 = 100 - date_field_name = rec.ks_date_filter_field_2.name - - ks_date_domain = ['&', (date_field_name, ">=", - fields.datetime.strftime(selected_start_date, - DEFAULT_SERVER_DATETIME_FORMAT)), - (date_field_name, "<=", - fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT))] - - for p in range(1, abs_year_period_2 + 1): - ks_date_domain.insert(0, '|') - ks_date_domain.extend(['&', (date_field_name, ">=", fields.datetime.strftime( - selected_start_date - relativedelta.relativedelta(years=p) * sign_yp, - DEFAULT_SERVER_DATETIME_FORMAT)), - (date_field_name, "<=", fields.datetime.strftime( - selected_end_date - relativedelta.relativedelta( - years=p) * sign_yp, - DEFAULT_SERVER_DATETIME_FORMAT))]) - else: - if rec.ks_date_filter_field_2: - selected_start_date = fields.datetime.strftime(selected_start_date, - DEFAULT_SERVER_DATETIME_FORMAT) - selected_end_date = fields.datetime.strftime(selected_end_date, - DEFAULT_SERVER_DATETIME_FORMAT) - ks_date_domain = [(rec.ks_date_filter_field_2.name, ">=", selected_start_date), - (rec.ks_date_filter_field_2.name, "<=", selected_end_date)] - else: - ks_date_domain = [] - elif selected_start_date and rec.ks_date_filter_field_2: - selected_start_date = fields.datetime.strftime(selected_start_date, DEFAULT_SERVER_DATETIME_FORMAT) - ks_date_domain = [(rec.ks_date_filter_field_2.name, ">=", selected_start_date)] - elif selected_end_date and rec.ks_date_filter_field_2: - selected_end_date = fields.datetime.strftime(selected_end_date, DEFAULT_SERVER_DATETIME_FORMAT) - ks_date_domain = [(rec.ks_date_filter_field_2.name, "<=", selected_end_date)] - else: - ks_date_domain = [] - - proper_domain = safe_eval(ks_domain_2) if ks_domain_2 else [] - if ks_date_domain: - proper_domain.extend(ks_date_domain) - if rec.ks_domain_extension_2: - ks_domain_extension = rec.ks_convert_domain_extension(rec.ks_domain_extension_2, rec) - proper_domain.extend(ks_domain_extension) - if domain: - proper_domain.extend(domain) - - return proper_domain - - def 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, ks_chart_groupby_type, orderby, - limit, chart_count, ks_chart_measure_field_ids, ks_chart_measure_field_2_ids, - ks_chart_groupby_relation_field_id, ks_chart_data): - - if ks_chart_groupby_type == "date_type": - ks_chart_groupby_field = ks_chart_groupby_relation_field + ":" + ks_chart_date_groupby - else: - ks_chart_groupby_field = ks_chart_groupby_relation_field - - try: - if self.ks_fill_temporal and ks_chart_date_groupby not in ['minute', 'hour']: - ks_chart_records = self.env[ks_model_name].with_context(fill_temporal=True) \ - .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) - else: - ks_chart_records = self.env[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])), [ks_chart_groupby_field], - orderby=orderby, limit=limit, lazy=False) - except Exception as e: - ks_chart_records = [] - pass - ks_chart_data['groupby'] = ks_chart_groupby_field - if ks_chart_groupby_type == "relational_type": - ks_chart_data['groupByIds'] = [] - - for res in ks_chart_records: - is_ks_index = False - ks_index = False - if all(measure_field in res for measure_field in ks_chart_measure_field): - if ks_chart_groupby_type == "relational_type": - if res[ks_chart_groupby_field]: - ks_chart_data['groupByIds'].append(res[ks_chart_groupby_field][0]) - label = res[ks_chart_groupby_field][1] - else: - label = res[ks_chart_groupby_field] - elif ks_chart_groupby_type == "selection": - selection = res[ks_chart_groupby_field] - if selection: - label = dict(self.env[ks_model_name].fields_get(allfields=[ks_chart_groupby_field]) - [ks_chart_groupby_field]['selection'])[selection] - else: - label = selection - else: - label = res[ks_chart_groupby_field] - - ks_chart_data['domains'].append(res.get('__domain', [])) - if label in ks_chart_data['labels']: - ks_index = ks_chart_data['labels'].index(label) - is_ks_index = True - - else: - ks_chart_data['labels'].append(label) - - counter = 0 - if ks_chart_measure_field: - if ks_chart_measure_field_2: - index = 0 - for field_rec in ks_chart_measure_field_2: - ks_groupby_equal_measures = res.get(ks_chart_groupby_relation_field + "_count", - False) or res.get("__count", False) \ - if res.get(ks_chart_groupby_relation_field + "_count", False) or res.get("__count", - False) \ - and ks_chart_measure_field_2_ids[index] == ks_chart_groupby_relation_field_id \ - else 1 - try: - if res.get('__count', False): - data = res[field_rec] * ks_groupby_equal_measures \ - if chart_count == 'sum' else \ - res[field_rec] - else: - data = 0 - if is_ks_index: - if chart_count == 'sum': - ks_chart_data['datasets'][counter]['data'][ks_index] += data - else: - ks_chart_data['datasets'][counter]['data'][ks_index] = \ - (ks_chart_data['datasets'][counter]['data'][ks_index] + data) / 2 - counter += 1 - index += 1 - continue - except ZeroDivisionError: - data = 0 - ks_chart_data['datasets'][counter]['data'].append(data) - counter += 1 - index += 1 - - index = 0 - for field_rec in ks_chart_measure_field: - ks_groupby_equal_measures = res.get(ks_chart_groupby_relation_field + "_count", - False) or res.get("__count", False) \ - if res.get(ks_chart_groupby_relation_field + "_count", False) or res.get("__count", False) \ - and ks_chart_measure_field_ids[index] == ks_chart_groupby_relation_field_id \ - else 1 - try: - if res.get('__count', False): - data = res[field_rec] * ks_groupby_equal_measures \ - if chart_count == 'sum' else \ - res[field_rec] - else: - data = 0 - if is_ks_index: - if chart_count == 'sum': - ks_chart_data['datasets'][counter]['data'][ks_index] += data - else: - ks_chart_data['datasets'][counter]['data'][ks_index] = \ - (ks_chart_data['datasets'][counter]['data'][ks_index] + data) / 2 - counter += 1 - index += 1 - continue - except ZeroDivisionError: - data = 0 - ks_chart_data['datasets'][counter]['data'].append(data) - counter += 1 - index += 1 - - else: - if res.get('__count'): - count = res[ks_chart_groupby_relation_field + "_count"] \ - if res.get((ks_chart_groupby_relation_field + "_count"), False) else res['__count'] - else: - count = 0 - data = count - ks_chart_data['datasets'][0]['data'].append(data) - - return ks_chart_data - - @api.model - def ks_fetch_drill_down_data(self, item_id, domain, sequence): - - record = self.browse(int(item_id)) - ks_chart_data = {'labels': [], 'datasets': [], 'ks_show_second_y_scale': False, 'domains': [], - 'previous_domain': domain, 'ks_currency': 0, 'ks_field': "", 'ks_selection': "", } - if record.ks_unit and record.ks_unit_selection == 'monetary': - ks_chart_data['ks_selection'] += record.ks_unit_selection - ks_chart_data['ks_currency'] += record.env.user.company_id.currency_id.id - elif record.ks_unit and record.ks_unit_selection == 'custom': - ks_chart_data['ks_selection'] += record.ks_unit_selection - if record.ks_chart_unit: - ks_chart_data['ks_field'] += record.ks_chart_unit - - # If count chart data type: - action_lines = record.ks_action_lines.sorted(key=lambda r: r.sequence) - action_line = action_lines[sequence] - 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', - 'fields_type': [], - '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 - else: - ks_chart_list_measure = record.ks_chart_measure_field - - 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 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 - ks_count = 0 - for ks in record.ks_action_lines: - ks_count += 1 - if action_line.ks_item_action_field.ttype == 'many2one': - ks_list_view_data['fields_type'].append(action_line.ks_item_action_field.ttype) - ks_list_view_data['list_view_type'] = 'relational_type' - ks_list_view_data['groupby'] = action_line.ks_item_action_field.name - ks_list_fields.append(action_line.ks_item_action_field.name) - ks_list_view_data['label'].append(action_line.ks_item_action_field.field_description) - for res in ks_chart_list_measure: - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_fields.append(res.name) - ks_list_view_data['label'].append(res.field_description) - - ks_list_view_records = self.env[record.ks_model_name] \ - .read_group(domain, ks_list_fields, [action_line.ks_item_action_field.name], orderby=orderby, - limit=limit, lazy=False) - for res in ks_list_view_records: - - counter = 0 - data_row = {'id': res[action_line.ks_item_action_field.name][0] if res[ - action_line.ks_item_action_field.name] else res[action_line.ks_item_action_field.name], - 'data': [], - 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, - '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] if res[field_rec] else "False") - else: - data_row['data'].append(res[field_rec]) - counter += 1 - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_row) - - elif action_line.ks_item_action_field.ttype == 'date' or \ - action_line.ks_item_action_field.ttype == 'datetime': - ks_list_view_data['list_view_type'] = 'date_type' - ks_list_field = [] - ks_list_view_data[ - 'groupby'] = action_line.ks_item_action_field.name + ':' + action_line.ks_item_action_date_groupby - ks_list_field.append( - action_line.ks_item_action_field.name + ':' + action_line.ks_item_action_date_groupby) - ks_list_fields.append(action_line.ks_item_action_field.name) - ks_list_view_data['label'].append( - action_line.ks_item_action_field.field_description) - ks_list_view_data['fields_type'].append(action_line.ks_item_action_field.ttype) - for res in ks_chart_list_measure: - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_fields.append(res.name) - ks_list_field.append(res.name) - ks_list_view_data['label'].append(res.field_description) - - ks_list_view_records = self.env[record.ks_model_name] \ - .read_group(domain, ks_list_fields, [action_line.ks_item_action_field.name + ':' + - action_line.ks_item_action_date_groupby], orderby=orderby, - limit=limit, lazy=False) - - for res in ks_list_view_records: - counter = 0 - data_row = {'data': [], - 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, - 'last_seq': ks_count, 'ks_column_type': []} - for field_rec in ks_list_field: - data_row['data'].append(res[field_rec]) - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_row) - - elif action_line.ks_item_action_field.ttype == 'selection': - ks_list_view_data['list_view_type'] = 'selection' - ks_list_view_data['fields_type'].append(action_line.ks_item_action_field.ttype) - ks_list_view_data['groupby'] = action_line.ks_item_action_field.name - ks_selection_field = action_line.ks_item_action_field.name - ks_list_view_data['label'].append(action_line.ks_item_action_field.field_description) - for res in ks_chart_list_measure: - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_fields.append(res.name) - ks_list_view_data['label'].append(res.field_description) - - ks_list_view_records = self.env[record.ks_model_name] \ - .read_group(domain, ks_list_fields, [action_line.ks_item_action_field.name], orderby=orderby, - limit=limit, lazy=False) - for res in ks_list_view_records: - counter = 0 - data_row = {'data': [], - 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, - 'last_seq': ks_count, 'ks_column_type': []} - if res[ks_selection_field]: - data_row['data'].append(dict( - self.env[record.ks_model_name].fields_get(allfields=ks_selection_field) - [ks_selection_field]['selection'])[res[ks_selection_field]]) - else: - data_row['data'].append(" ") - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - for field_rec in ks_list_fields: - data_row['data'].append(res[field_rec]) - data_row['ks_column_type'].append(self.ks_chart_relation_groupby.ttype) - ks_list_view_data['data_rows'].append(data_row) - - else: - ks_list_view_data['list_view_type'] = 'other' - ks_list_view_data['groupby'] = action_line.ks_item_action_field.name - ks_list_view_data['fields_type'].append(action_line.ks_item_action_field.ttype) - ks_list_fields.append(action_line.ks_item_action_field.name) - ks_list_view_data['label'].append(action_line.ks_item_action_field.field_description) - for res in ks_chart_list_measure: - if action_line.ks_item_action_field.name != res.name: - ks_list_view_data['fields_type'].append(res.ttype) - ks_list_view_data['label'].append(res.field_description) - ks_list_fields.append(res.name) - - ks_list_view_records = self.env[record.ks_model_name] \ - .read_group(domain, ks_list_fields, [action_line.ks_item_action_field.name], orderby=orderby, - limit=limit, lazy=False) - for res in ks_list_view_records: - if all(list_fields in res for list_fields in ks_list_fields): - counter = 0 - data_row = {'id': action_line.ks_item_action_field.name, 'data': [], - 'domain': json.dumps(res['__domain']), 'sequence': sequence + 1, - 'last_seq': ks_count, 'ks_column_type': []} - - for field_rec in ks_list_fields: - if counter == 0: - data_row['data'].append(res[field_rec]) - else: - if action_line.ks_item_action_field.name == field_rec: - data_row['data'].append(res[field_rec] * ( - res.get(field_rec + '_count', False) if res.get(field_rec + '_count', - False) else res.get('__count'))) - else: - data_row['data'].append(res[field_rec]) - counter += 1 - data_row['ks_column_type'].append(action_line.ks_item_action_field.ttype) - ks_list_view_data['data_rows'].append(data_row) - if record.ks_multiplier_active: - for ks_multiplier in record.ks_multiplier_lines: - label = ks_multiplier.ks_multiplier_fields.field_description - if label in ks_list_view_data['label']: - index = ks_list_view_data['label'].index(label) - for i in range(0, len(ks_list_view_data['data_rows'])): - data_values = ks_list_view_data['data_rows'][i]['data'][ - 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, 'ks_action_name': "".join(ks_action_name.split(" "))} - else: - 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 record.ks_chart_data_count_type == "count": - if not action_line.ks_sort_by_field: - ks_chart_measure_field_with_type.append('count:count(id)') - elif action_line.ks_sort_by_field: - if not action_line.ks_sort_by_field.ttype == "datetime": - ks_chart_measure_field_with_type.append(action_line.ks_sort_by_field.name + ':' + 'sum') - else: - ks_chart_measure_field_with_type.append(action_line.ks_sort_by_field.name) - - ks_chart_data['datasets'].append({'data': [], 'label': "Count"}) - else: - if ks_chart_type == 'ks_bar_chart': - if record.ks_chart_measure_field_2: - ks_chart_data['ks_show_second_y_scale'] = True - - for res in record.ks_chart_measure_field_2: - if record.ks_chart_data_count_type == 'sum': - ks_data_count_type = 'sum' - elif record.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'}) - if record.ks_dashboard_item_type == 'ks_list_view': - for res in record.ks_list_view_group_fields: - ks_chart_measure_field.append(res.name) - ks_chart_measure_field_with_type.append(res.name + ':' + 'sum') - ks_chart_measure_field_ids.append(res.id) - ks_chart_data['datasets'].append({'data': [], 'label': res.field_description}) - else: - for res in record.ks_chart_measure_field: - if record.ks_chart_data_count_type == 'sum': - ks_data_count_type = 'sum' - elif record.ks_chart_data_count_type == 'average': - ks_data_count_type = 'avg' - else: - raise ValidationError(_('Please chose any Data Type!')) - ks_chart_measure_field.append(res.name) - ks_chart_measure_field_with_type.append(res.name + ':' + ks_data_count_type) - ks_chart_measure_field_ids.append(res.id) - ks_chart_data['datasets'].append({'data': [], 'label': res.field_description}) - - ks_chart_groupby_relation_field = action_line.ks_item_action_field.name - ks_chart_relation_type = action_line.ks_item_action_field_type - ks_chart_date_group_by = action_line.ks_item_action_date_groupby - ks_chart_groupby_relation_field_id = action_line.ks_item_action_field.id - # orderby = action_line.ks_sort_by_field.name if action_line.ks_sort_by_field else "id" - 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 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 - - if ks_chart_type != "ks_bar_chart": - ks_chart_measure_field_2 = [] - ks_chart_measure_field_2_ids = [] - - ks_chart_data = record.ks_fetch_chart_data(record.ks_model_name, 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_group_by, - ks_chart_relation_type, - orderby, limit, record.ks_chart_data_count_type, - ks_chart_measure_field_ids, - ks_chart_measure_field_2_ids, ks_chart_groupby_relation_field_id, - ks_chart_data) - if record.ks_multiplier_active: - for ks_multiplier in record.ks_multiplier_lines: - for i in range(0, len(ks_chart_data['datasets'])): - 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 - return { - 'ks_chart_data': json.dumps(ks_chart_data), - 'ks_chart_type': ks_chart_type, - 'ks_action_name': "".join(ks_action_name.split(" ")), - 'ks_action_id':ks_action_id, - 'sequence': sequence + 1 - } - - @api.model - def ks_get_start_end_date(self, model_name, ks_chart_groupby_relation_field, ttype, ks_chart_domain, - ks_goal_domain): - ks_start_end_date = {} - try: - model_field_start_date = \ - self.env[model_name].search(ks_chart_domain + [(ks_chart_groupby_relation_field, '!=', False)], limit=1, - order=ks_chart_groupby_relation_field + " ASC")[ - ks_chart_groupby_relation_field] - model_field_end_date = \ - self.env[model_name].search(ks_chart_domain + [(ks_chart_groupby_relation_field, '!=', False)], limit=1, - order=ks_chart_groupby_relation_field + " DESC")[ - ks_chart_groupby_relation_field] - except Exception as e: - model_field_start_date = model_field_end_date = False - pass - # if model_field_start_date and model_field_end_date: - # goal_model_start_date = \ - # self.env['ks_dashboard_ninja.item_goal'].search([('ks_goal_date', '>=', model_field_start_date.strftime("%Y-%m-%d")), - # ('ks_goal_date', '<=', model_field_end_date.strftime("%Y-%m-%d"))], limit=1, - # order='ks_goal_date ASC')['ks_goal_date'] - # goal_model_end_date = \ - # self.env['ks_dashboard_ninja.item_goal'].search([('ks_goal_date', '>=', model_field_start_date.strftime("%Y-%m-%d")), - # ('ks_goal_date', '<=', model_field_end_date.strftime("%Y-%m-%d"))], limit=1, - # order='ks_goal_date DESC')['ks_goal_date'] - # else: - - goal_model_start_date = \ - self.env['ks_dashboard_ninja.item_goal'].search(ks_goal_domain, limit=1, - order='ks_goal_date ASC')['ks_goal_date'] - goal_model_end_date = \ - self.env['ks_dashboard_ninja.item_goal'].search(ks_goal_domain, limit=1, - order='ks_goal_date DESC')['ks_goal_date'] - - if model_field_start_date and ttype == "date": - model_field_end_date = datetime.combine(model_field_end_date, datetime.min.time()) - model_field_start_date = datetime.combine(model_field_start_date, datetime.min.time()) - - if model_field_start_date and goal_model_start_date: - goal_model_start_date = datetime.combine(goal_model_start_date, datetime.min.time()) - goal_model_end_date = datetime.combine(goal_model_end_date, datetime.max.time()) - if model_field_start_date < goal_model_start_date: - ks_start_end_date['start_date'] = model_field_start_date.strftime("%Y-%m-%d 00:00:00") - else: - ks_start_end_date['start_date'] = goal_model_start_date.strftime("%Y-%m-%d 00:00:00") - if model_field_end_date > goal_model_end_date: - ks_start_end_date['end_date'] = model_field_end_date.strftime("%Y-%m-%d 23:59:59") - else: - ks_start_end_date['end_date'] = goal_model_end_date.strftime("%Y-%m-%d 23:59:59") - - elif model_field_start_date and not goal_model_start_date: - ks_start_end_date['start_date'] = model_field_start_date.strftime("%Y-%m-%d 00:00:00") - ks_start_end_date['end_date'] = model_field_end_date.strftime("%Y-%m-%d 23:59:59") - - elif goal_model_start_date and not model_field_start_date: - ks_start_end_date['start_date'] = goal_model_start_date.strftime("%Y-%m-%d 00:00:00") - ks_start_end_date['end_date'] = goal_model_end_date.strftime("%Y-%m-%d 23:59:59") - else: - ks_start_end_date['start_date'] = False - ks_start_end_date['end_date'] = False - - return ks_start_end_date - - # List View pagination - @api.model - def ks_get_next_offset(self, ks_item_id, offset, item_domain=[]): - record = self.browse(ks_item_id) - ks_offset = offset['offset'] - ks_list_domain = self.ks_convert_into_proper_domain(record.ks_domain, self, item_domain) - if self.ks_list_view_type == 'grouped': - orderby = record.ks_sort_by_field.id - sort_order = record.ks_sort_by_order - ks_list_view_data = self.get_list_view_record(orderby, sort_order, ks_list_domain, ksoffset=int(ks_offset)) - - else: - ks_list_view_data = self.ks_fetch_list_view_data(record, ks_list_domain, offset=int(ks_offset)) - - return { - 'ks_list_view_data': json.dumps(ks_list_view_data), - 'offset': int(ks_offset) + 1, - 'next_offset': int(ks_offset) + len(ks_list_view_data['data_rows']), - 'limit': record.ks_record_data_limit if record.ks_record_data_limit else 0, - } - - @api.model - def get_sorted_month(self, display_format, ftype='date'): - query = """ - with d as (SELECT date_trunc(%(aggr)s, generate_series) AS timestamp FROM generate_series - (%(timestamp_begin)s::TIMESTAMP , %(timestamp_end)s::TIMESTAMP , %(aggr1)s::interval )) - select timestamp from d group by timestamp order by timestamp - """ - self.env.cr.execute(query, { - 'timestamp_begin': "2020-01-01 00:00:00", - 'timestamp_end': "2020-12-31 00:00:00", - 'aggr': 'month', - 'aggr1': '1 month' - }) - - dates = self.env.cr.fetchall() - locale = self._context.get('lang') or 'en_US' - tz_convert = self._context.get('tz') - return [self.format_label(d[0], ftype, display_format, tz_convert, locale) for d in dates] - - # Fix Order BY : maybe revert old code - @api.model - def generate_timeserise(self, date_begin, date_end, aggr, ftype='date'): - query = """ - with d as (SELECT date_trunc(%(aggr)s, generate_series) AS timestamp FROM generate_series - (%(timestamp_begin)s::TIMESTAMP , %(timestamp_end)s::TIMESTAMP , '1 hour'::interval )) - select timestamp from d group by timestamp order by timestamp - """ - - self.env.cr.execute(query, { - 'timestamp_begin': date_begin, - 'timestamp_end': date_end, - 'aggr': aggr, - 'aggr1': '1 ' + aggr - }) - dates = self.env.cr.fetchall() - display_formats = { - # Careful with week/year formats: - # - yyyy (lower) must always be used, except for week+year formats - # - YYYY (upper) must always be used for week+year format - # e.g. 2006-01-01 is W52 2005 in some locales (de_DE), - # and W1 2006 for others - # - # Mixing both formats, e.g. 'MMM YYYY' would yield wrong results, - # such as 2006-01-01 being formatted as "January 2005" in some locales. - # Cfr: http://babel.pocoo.org/en/latest/dates.html#date-fields - 'minute': 'hh:mm dd MMM', - 'hour': 'hh:00 dd MMM', - 'day': 'dd MMM yyyy', # yyyy = normal year - 'week': "'W'w YYYY", # w YYYY = ISO week-year - 'month': 'MMMM yyyy', - 'quarter': 'QQQ yyyy', - 'year': 'yyyy', - } - - display_format = display_formats[aggr] - locale = self._context.get('lang') or 'en_US' - tz_convert = self._context.get('tz') - return [self.format_label(d[0], ftype, display_format, tz_convert, locale) for d in dates] - - @api.model - def format_label(self, value, ftype, display_format, tz_convert, locale): - - tzinfo = None - if ftype == 'datetime': - if tz_convert: - value = pytz.timezone(self._context['tz']).localize(value) - tzinfo = value.tzinfo - return babel.dates.format_datetime(value, format=display_format, tzinfo=tzinfo, locale=locale) - else: - - if tz_convert: - value = pytz.timezone(self._context['tz']).localize(value) - tzinfo = value.tzinfo - return babel.dates.format_date(value, format=display_format, locale=locale) - - def ks_sort_sub_group_by_records(self, ks_data, field_type, ks_chart_date_groupby, ks_sort_by_order, - ks_chart_date_sub_groupby): - if ks_data: - reverse = False - if ks_sort_by_order == 'DESC': - reverse = True - - for data in ks_data: - if field_type == 'date_type': - if ks_chart_date_groupby in ['minute', 'hour']: - if ks_chart_date_sub_groupby in ["month", "week", "quarter", "year"]: - ks_sorted_months = self.get_sorted_month("MMM") - data['value'].sort(key=lambda x: int( - str(ks_sorted_months.index(x['x'].split(" ")[2]) + 1) + x['x'].split(" ")[1] + - x['x'].split(" ")[0].replace(":", "")), reverse=reverse) - else: - data['value'].sort(key=lambda x: int(x['x'].replace(":", "")), reverse=reverse) - elif ks_chart_date_groupby == 'day' and ks_chart_date_sub_groupby in ["quarter", "year"]: - ks_sorted_days = self.generate_timeserise("2020-01-01 00:00:00", "2020-12-31 00:00:00", - 'day', "date") - b = [" ".join(x.split(" ")[0:2]) for x in ks_sorted_days] - data['value'].sort(key=lambda x: b.index(x['x']), reverse=reverse) - elif ks_chart_date_groupby == 'day' and ks_chart_date_sub_groupby not in ["quarter", "year"]: - data['value'].sort(key=lambda i: int(i['x']), reverse=reverse) - elif ks_chart_date_groupby == 'week': - data['value'].sort(key=lambda i: int(i['x'][1:]), reverse=reverse) - elif ks_chart_date_groupby == 'month': - ks_sorted_months = self.generate_timeserise("2020-01-01 00:00:00", "2020-12-31 00:00:00", - 'month', "date") - b = [" ".join(x.split(" ")[0:1]) for x in ks_sorted_months] - data['value'].sort(key=lambda x: b.index(x['x']), reverse=reverse) - elif ks_chart_date_groupby == 'quarter': - ks_sorted_months = self.generate_timeserise("2020-01-01 00:00:00", "2020-12-31 00:00:00", - 'quarter', "date") - b = [" ".join(x.split(" ")[:-1]) for x in ks_sorted_months] - data['value'].sort(key=lambda x: b.index(x['x']), reverse=reverse) - elif ks_chart_date_groupby == 'year': - data['value'].sort(key=lambda i: int(i['x']), reverse=reverse) - else: - data['value'].sort(key=lambda i: i['x'], reverse=reverse) - - return ks_data - - @api.onchange('ks_domain_2') - def ks_onchange_check_domain_2_onchange(self): - if self.ks_domain_2: - proper_domain_2 = [] - try: - ks_domain_2 = self.ks_domain_2 - if "%UID" in ks_domain_2: - ks_domain_2 = ks_domain_2.replace("%UID", str(self.env.user.id)) - if "%MYCOMPANY" in ks_domain_2: - ks_domain_2 = replace_company_domain(ks_domain_2, self.env.company.id, self.env.companies.ids) - ks_domain_2 = safe_eval(ks_domain_2) - - for element in ks_domain_2: - proper_domain_2.append(element) if type(element) != list else proper_domain_2.append(tuple(element)) - self.env[self.ks_model_name_2].search_count(proper_domain_2) - except Exception: - raise UserError("Invalid Domain") - - @api.onchange('ks_domain') - def ks_onchange_check_domain_onchange(self): - if self.ks_domain: - proper_domain = [] - try: - ks_domain = self.ks_domain - if "%UID" in ks_domain: - ks_domain = ks_domain.replace("%UID", str(self.env.user.id)) - if "%MYCOMPANY" in ks_domain: - ks_domain = replace_company_domain(ks_domain, self.env.company.id, self.env.companies.ids) - ks_domain = safe_eval(ks_domain) - for element in ks_domain: - proper_domain.append(element) if type(element) != list else proper_domain.append(tuple(element)) - self.env[self.ks_model_name].search_count(proper_domain) - except Exception: - raise UserError("Invalid Domain") - - # @api.onchange('ks_dashboard_item_type', 'ks_model_id') - # def onchange_dashboard_item_type(self): - # if self.ks_dashboard_item_type == 'ks_map_view' and self.ks_model_id: - # models = ['sale.order', 'purchase.order', 'account.move', 'stock.picking', 'crm.lead'] - # has_partner = self.ks_model_id.model in models - # if not has_partner: - # raise UserError(_("Selected model is not supported for Map View.")) - - @api.depends('ks_dashboard_item_type', 'ks_model_id') - def _compute_map_partners(self): - for rec in self: - rec.ks_partners_map = "" - domain = [] - if rec.ks_dashboard_item_type == 'ks_map_view' and rec.ks_model_name: - if rec.ks_domain: - domain = rec._get_domain() - records = self.env[rec.ks_model_name].search(domain) - if records: - if rec.ks_model_name == 'res.partner': - rec.ks_partners_map = records.ids - else: - if 'partner_id' in records: - partners = records.mapped('partner_id') - rec.ks_partners_map = partners.ids - else: - raise UserError(_("Selected model is not supported for Map View.")) - - - def _get_domain(self): - ks_domain = ast.literal_eval(self.ks_domain) - domain = [] - for rec in ks_domain: - domain.append(tuple(rec)) - return domain - - @api.depends('ks_country_id') - def _compute_bounds(self): - for rec in self: - rec.ks_bounds = [[6.554607, 68.1097], [35.674545, 97.395358]] - new_bounds = get_country_code(rec.ks_country_code) - if new_bounds: - new_bounds = new_bounds[1] - rec.ks_bounds = [[new_bounds[1], new_bounds[0]], [new_bounds[3], new_bounds[2]]] - - -class KsDashboardItemsGoal(models.Model): - _name = 'ks_dashboard_ninja.item_goal' - _description = 'Dashboard Ninja Items Goal Lines' - - ks_goal_date = fields.Date(string="Date") - ks_goal_value = fields.Float(string="Value") - - ks_dashboard_item = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") - -class KsDashboardCsvGroupBy(models.Model): - _name = 'ks.dashboard.csv.group.by' - _description = 'Dashboard Ninja Group By' - _rec_name = 'name' - - 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'), ('date', 'date'), ('datetime', 'datetime'), ('float', 'float'), - ('integer', 'integer')], - string='Type') - -class KsDashboardCsvNew(models.Model): - _name = 'ks.dashboard.csv.new' - _description = 'Dashboard Ninja New' - _rec_name = 'name' - - # ks_dashboard_group_by_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") - name = fields.Char(string="Name") - ttype = fields.Selection([('char', 'char'), ('date', 'date'), ('datetime', 'datetime'), ('float', 'float'), - ('integer', 'integer')], - string='Type') - - -class KsDashboardGroupBy(models.Model): - _name = 'ks.dashboard.group.by' - _description = 'Dashboard Ninja Group By' - _rec_name = 'name' - - ks_dashboard_group_by_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item Id") - name = fields.Char(string="Name") - ttype = fields.Selection([('char', 'char'), ('date', 'date'), ('datetime', 'datetime'), ('float', 'float'), - ('integer', 'integer')], - string='Type') - - -class KsDashboardNew(models.Model): - _name = 'ks.dashboard.new' - _description = 'Dashboard Ninja New' - _rec_name = 'name' - - # ks_dashboard_group_by_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") - name = fields.Char(string="Name") - ttype = fields.Selection([('char', 'char'), ('date', 'date'), ('datetime', 'datetime'), ('float', 'float'), - ('integer', 'integer')], - string='Type') - - -class KsDashboardItemsActions(models.Model): - _name = 'ks_dashboard_ninja.item_action' - _description = 'Dashboard Ninja Items Action Lines' - - ks_item_action_field = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store','=',True)," - "('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) - - ks_item_action_date_groupby = fields.Selection([('minute', 'Minute'), - ('hour', 'Hour'), - ('day', 'Day'), - ('week', 'Week'), - ('month', 'Month'), - ('quarter', 'Quarter'), - ('year', 'Year'), - ], string="Group By Date") - - ks_chart_type = fields.Selection([('ks_bar_chart', 'Bar Chart'), - ('ks_horizontalBar_chart', 'Horizontal Bar Chart'), - ('ks_line_chart', 'Line Chart'), - ('ks_area_chart', 'Area Chart'), - ('ks_pie_chart', 'Pie Chart'), - ('ks_doughnut_chart', 'Doughnut Chart'), - ('ks_polarArea_chart', 'Polar Area Chart'), - ('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'), - ('ks_bullet_chart', 'Bullet Chart')], - string="Item Type") - - ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") - ks_model_id = fields.Many2one('ir.model', related='ks_dashboard_item_id.ks_model_id') - sequence = fields.Integer(string="Sequence") - # For sorting and record limit - ks_record_limit = fields.Integer(string="Record Limit") - ks_sort_by_field = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence'),('store','=',True)," - "('ttype','!=','one2many'),('ttype','!=','many2one')," - "('ttype','!=','binary')]", - string="Sort By Field") - 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: - if rec.ks_item_action_field.ttype == 'datetime' or rec.ks_item_action_field.ttype == 'date': - rec.ks_item_action_field_type = 'date_type' - elif rec.ks_item_action_field.ttype == 'many2one': - rec.ks_item_action_field_type = 'relational_type' - elif rec.ks_item_action_field.ttype == 'selection': - rec.ks_item_action_field_type = 'selection' - - else: - rec.ks_item_action_field_type = 'none' - - @api.onchange('ks_item_action_date_groupby') - def ks_check_date_group_by(self): - for rec in self: - if rec.ks_item_action_field.ttype == 'date' and rec.ks_item_action_date_groupby in ['hour', 'minute']: - raise ValidationError(_('Action field: {} cannot be aggregated by {}').format( - rec.ks_item_action_field.display_name, rec.ks_item_action_date_groupby)) - - @api.onchange('ks_item_action_field') - def ks_onchange_item_action(self): - for rec in self: - if not (rec.ks_item_action_field.ttype == 'datetime' or rec.ks_item_action_field.ttype == 'date'): - rec.ks_item_action_date_groupby = False - -class KsDashboardItemMultiplier(models.Model): - _name = 'ks_dashboard_item.multiplier' - _description = 'Dashboard Ninja Items Multiplier Lines' - - ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") - ks_model_id = fields.Many2one('ir.model', related='ks_dashboard_item_id.ks_model_id') - ks_multiplier_value = fields.Float(string="Multiplier", default=1) - ks_multiplier_fields = fields.Many2one('ir.model.fields', - domain="[('model_id','=',ks_model_id),('name','!=','id'),('name','!=','sequence')," - "('store','=',True),'|','|'," - "('ttype','=','integer'),('ttype','=','float')," - "('ttype','=','monetary')]", - string="Multiplier Field") - - - - ## in labels ._value is not working #### \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/models/ks_dashboard_templates.py b/addons/ks_dashboard_ninja/models/ks_dashboard_templates.py deleted file mode 100644 index e3b661e..0000000 --- a/addons/ks_dashboard_ninja/models/ks_dashboard_templates.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- - -from odoo import models, fields, api - - -class KsDashboardNinjaTemplate(models.Model): - _name = 'ks_dashboard_ninja.board_template' - _description = 'Dashboard Ninja Template' - - name = fields.Char() - ks_gridstack_config = fields.Char() - ks_item_count = fields.Integer() - ks_template_type = fields.Selection([('ks_default', 'Predefined'), ('ks_custom', 'Custom')], - string="Template Format") - ks_dashboard_item_ids = fields.One2many('ks_dashboard_ninja.item', 'ks_dashboard_board_template_id', - string="Template Type") - ks_dashboard_board_id = fields.Many2one('ks_dashboard_ninja.board', string="Dashboard", help=""" - Items Configuration and their position in the dashboard will be copied from the selected dashboard - and will be saved as template. - """) - - @api.model_create_multi - def create(self, vals_list): - for val in vals_list: - if val.get('ks_template_type', False) and val.get('ks_dashboard_board_id', False): - dashboard_id = self.env['ks_dashboard_ninja.board'].browse(val.get('ks_dashboard_board_id')) - val['ks_gridstack_config'] = dashboard_id.ks_gridstack_config - val['ks_item_count'] = len(dashboard_id.ks_dashboard_items_ids) - val['ks_dashboard_item_ids'] = [(4, x.copy({'ks_dashboard_ninja_board_id': False}).id) for x in - dashboard_id.ks_dashboard_items_ids] - recs = super(KsDashboardNinjaTemplate, self).create(vals_list) - return recs - - def write(self, val): - if val.get('ks_dashboard_board_id', False): - dashboard_id = self.env['ks_dashboard_ninja.board'].browse(val.get('ks_dashboard_board_id')) - val['ks_gridstack_config'] = dashboard_id.ks_gridstack_config - val['ks_item_count'] = len(dashboard_id.ks_dashboard_items_ids) - val['ks_dashboard_item_ids'] = [(6, 0, - [x.copy({'ks_dashboard_ninja_board_id': False}).id for x in - dashboard_id.ks_dashboard_items_ids])] - recs = super(KsDashboardNinjaTemplate, self).write(val) - return recs diff --git a/addons/ks_dashboard_ninja/models/ks_dn_to_do_item.py b/addons/ks_dashboard_ninja/models/ks_dn_to_do_item.py deleted file mode 100644 index bc17590..0000000 --- a/addons/ks_dashboard_ninja/models/ks_dn_to_do_item.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- - -import json -import re - -from odoo.exceptions import ValidationError - -from odoo import models, fields, api, _ - - -class KsDashboardNinjaItems(models.Model): - _inherit = 'ks_dashboard_ninja.item' - - ks_to_do_preview = fields.Char("To Do Preview", default="To Do Preview") - ks_dn_header_lines = fields.One2many('ks_to.do.headers', 'ks_dn_item_id') - ks_to_do_data = fields.Char(string="To Do Data in JSon", compute='ks_get_to_do_view_data', compute_sudo=False) - ks_header_bg_color = fields.Char(string="Header Background Color", default="#8e24aa,0.99", - help=' Select the background color with transparency. ') - - @api.depends('ks_dn_header_lines', 'ks_dashboard_item_type') - def ks_get_to_do_view_data(self): - for rec in self: - ks_to_do_data = rec._ksGetToDOData() - rec.ks_to_do_data = ks_to_do_data - - def _ksGetToDOData(self): - ks_to_do_data = { - '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)) - - 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: - 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): - _name = 'ks_to.do.headers' - _description = "to do headers" - - ks_dn_item_id = fields.Many2one('ks_dashboard_ninja.item') - ks_to_do_header = fields.Char('Header') - ks_to_do_description_lines = fields.One2many('ks_to.do.description', 'ks_to_do_header_id') - - @api.constrains('ks_to_do_header') - def ks_to_do_header_check(self): - for rec in self: - if rec.ks_to_do_header: - ks_check = bool(re.match('^[A-Z, a-z,0-9,_]+$', rec.ks_to_do_header)) - if not ks_check: - raise ValidationError(_("Special characters are not allowed only string and digits allow for section header")) - - @api.onchange('ks_to_do_header') - def ks_to_do_header_onchange(self): - for rec in self: - if rec.ks_to_do_header: - ks_check = bool(re.match('^[A-Z, a-z,0-9,_]+$', rec.ks_to_do_header)) - if not ks_check: - raise ValidationError(_("Special characters are not allowed only string and digits allow for section header")) - -class KsToDODescription(models.Model): - _name = 'ks_to.do.description' - _description = 'to do description' - - ks_to_do_header_id = fields.Many2one('ks_to.do.headers') - ks_description = fields.Text('Description') - ks_active = fields.Boolean('Active Description', default=True) diff --git a/addons/ks_dashboard_ninja/models/ks_import_dashboard.py b/addons/ks_dashboard_ninja/models/ks_import_dashboard.py deleted file mode 100644 index 91065ae..0000000 --- a/addons/ks_dashboard_ninja/models/ks_import_dashboard.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -import base64 -import logging - -from odoo.exceptions import ValidationError - -from odoo import fields, models, _ - -_logger = logging.getLogger(__name__) - - -class KsDashboardNInjaImport(models.TransientModel): - _name = 'ks_dashboard_ninja.import' - _description = 'Import Dashboard' - - ks_import_dashboard = fields.Binary(string="Upload Dashboard", attachment=True) - ks_top_menu_id = fields.Many2one('ir.ui.menu', string="Show Under Menu", domain="[('parent_id','=',False)]", - required=True, - default=lambda self: self.env['ir.ui.menu'].search( - [('name', '=', 'My Dashboards')])) - - def ks_do_action(self): - for rec in self: - try: - ks_result = base64.b64decode(rec.ks_import_dashboard) - self.env['ks_dashboard_ninja.board'].ks_import_dashboard(ks_result, self.ks_top_menu_id) - return { - 'type': 'ir.actions.client', - 'tag': 'reload', - } - except Exception as E: - _logger.warning(E) - raise ValidationError(_(str(E))) diff --git a/addons/ks_dashboard_ninja/models/ks_item_action.py b/addons/ks_dashboard_ninja/models/ks_item_action.py deleted file mode 100644 index d17b3af..0000000 --- a/addons/ks_dashboard_ninja/models/ks_item_action.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- - -from odoo import models, fields - - -class KsDashboardNinjaBoardItemAction(models.TransientModel): - _name = 'ks_ninja_dashboard.item_action' - _description = 'Dashboard Ninja Item Actions' - - name = fields.Char() - ks_dashboard_item_ids = fields.Many2many("ks_dashboard_ninja.item", string="Dashboard Items") - ks_action = fields.Selection([('move', 'Move'), - ('duplicate', 'Duplicate'), - ], string="Action") - ks_dashboard_ninja_id = fields.Many2one("ks_dashboard_ninja.board", string="Select Dashboard") - ks_dashboard_ninja_ids = fields.Many2many("ks_dashboard_ninja.board", string="Select Dashboards") - - # Move or Copy item to another dashboard action - - def action_item_move_copy_action(self): - if self.ks_action == 'move': - for item in self.ks_dashboard_item_ids: - item.ks_dashboard_ninja_board_id = self.ks_dashboard_ninja_id - elif self.ks_action == 'duplicate': - # Using sudo here to allow creating same item without any security error - for dashboard_id in self.ks_dashboard_ninja_ids: - for item in self.ks_dashboard_item_ids: - item.sudo().copy({'ks_dashboard_ninja_board_id': dashboard_id.id}) diff --git a/addons/ks_dashboard_ninja/models/ks_key_fetch.py b/addons/ks_dashboard_ninja/models/ks_key_fetch.py deleted file mode 100644 index 17af209..0000000 --- a/addons/ks_dashboard_ninja/models/ks_key_fetch.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -import json -import logging - -import requests -from odoo.exceptions import ValidationError - -from odoo import fields, models, _ - -_logger = logging.getLogger(__name__) - - -class KsAIDashboardFetch(models.TransientModel): - _name = 'ks_dashboard_ninja.fetch_key' - _description = 'Fetch API key' - - ks_email_id = fields.Char(string="Email ID") - ks_api_key =fields.Char(string="Generated AI API Key") - ks_show_api_key = fields.Boolean(string="Show key",default=False) - - def ks_fetch_details(self): - url = self.env['ir.config_parameter'].sudo().get_param( - 'ks_dashboard_ninja.url') - if url and self.ks_email_id: - url = url + "/api/v1/ks_dn_fetch_api" - json_data = {'email':self.ks_email_id} - ks_ai_response = requests.post(url,data=json_data) - if ks_ai_response.status_code == 200: - ks_ai_response = json.loads(ks_ai_response.text) - self.ks_api_key = ks_ai_response - self.ks_show_api_key = True - else: - raise ValidationError(_("Error generates with following status %s"),ks_ai_response.status_code) diff --git a/addons/ks_dashboard_ninja/models/res_settings.py b/addons/ks_dashboard_ninja/models/res_settings.py deleted file mode 100644 index c5e8a59..0000000 --- a/addons/ks_dashboard_ninja/models/res_settings.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- - -import json - -import requests -from odoo.exceptions import ValidationError - -from odoo import fields, models, _ - - -class ResConfig(models.TransientModel): - _inherit = "res.config.settings" - - dn_api_key = fields.Char(string="Dashboard AI API Key",store=True, - config_parameter='ks_dashboard_ninja.dn_api_key') - enable_chart_zoom = fields.Boolean(string="Enable Zooming for charts", store=True, - config_parameter='ks_dashboard_ninja.enable_chart_zoom') - 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: - url = self.url + "/api/v1/ks_dn_fetch_api" - json_data = {'email':self.ks_email_id, - 'url':self.env['ir.config_parameter'].sudo().get_param('web.base.url'), - 'db_name':self.env.cr.dbname - } - ks_ai_response = requests.post(url,data=json_data) - except Exception as e: - raise ValidationError(_("Please enter correct URL")) - if ks_ai_response.status_code == 200: - try: - ks_ai_response = json.loads(ks_ai_response.text) - except Exception as e: - ks_ai_response = False - if ks_ai_response == "success": - return { - 'type': 'ir.actions.client', - 'tag': 'display_notification', - 'params': { - 'title': _('Success'), - 'message': 'API key sent on Email ID', - 'sticky': False, - } - } - elif ks_ai_response == 'key already generated': - raise ValidationError( - _("key already generated.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")) - else: - 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/addons/ks_dashboard_ninja/requirements.txt b/addons/ks_dashboard_ninja/requirements.txt deleted file mode 100644 index 2a6c782..0000000 --- a/addons/ks_dashboard_ninja/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -xlrd==2.0.1 -openpyxl == 3.1.2 -gTTS == 2.5.1 -pandas==2.1.2 -SQLAlchemy==2.0.32 diff --git a/addons/ks_dashboard_ninja/security/ir.model.access.csv b/addons/ks_dashboard_ninja/security/ir.model.access.csv deleted file mode 100644 index 667cf1c..0000000 --- a/addons/ks_dashboard_ninja/security/ir.model.access.csv +++ /dev/null @@ -1,36 +0,0 @@ -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,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,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,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,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 -access_ks_dashboard_ninja_favourite_filters,ks_dashboard_ninja.favourite_filters,model_ks_dashboard_ninja_favourite_filters,,1,1,1,1 diff --git a/addons/ks_dashboard_ninja/security/ks_security_groups.xml b/addons/ks_dashboard_ninja/security/ks_security_groups.xml deleted file mode 100644 index 6db28cb..0000000 --- a/addons/ks_dashboard_ninja/security/ks_security_groups.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Dashboard Item Company Restriction: User Can only view their company and sub companies - items. - - - - ['|',('ks_company_id','in', company_ids),('ks_company_id','=',False)] - - - - - - - - Dashboard Record Level Groups Access: Show dashboards matching user's assigned groups. - - ['|', ('ks_dashboard_group_access', '=' , False), ('ks_dashboard_group_access','in', user.groups_id.ids)] - - - - - Child Dashboard Record Level Groups Access: Show dashboards matching user's assigned groups. - - ['|', ('ks_computed_group_access', '=', False), ('ks_computed_group_access', 'in', user.groups_id.ids)] - - - - - Dashboard Record Level Groups Access: Show all dashboards to admin regardless of assigned groups. - - [(1, '=', 1)] - - - - - Child Dashboard Record Level Groups Access: Show all dashboards to admin regardless of assigned groups. - - [(1, '=', 1)] - - - - - Dashboard Ninja Rights - - - - Show Full Dashboard Features - - - - - - - - - \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/static/description/DN-5.gif b/addons/ks_dashboard_ninja/static/description/DN-5.gif deleted file mode 100644 index 5e50478..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/DN-5.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/css/bootstrap.min.css b/addons/ks_dashboard_ninja/static/description/css/bootstrap.min.css deleted file mode 100644 index 6ee5956..0000000 --- a/addons/ks_dashboard_ninja/static/description/css/bootstrap.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * 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/addons/ks_dashboard_ninja/static/description/icon.png b/addons/ks_dashboard_ninja/static/description/icon.png deleted file mode 100644 index 3e9bcc9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/icon.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Advanced-Date-Filter.png b/addons/ks_dashboard_ninja/static/description/img/Advanced-Date-Filter.png deleted file mode 100644 index 9f23cd9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Advanced-Date-Filter.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Create-Charts-From-EXCEL-AND-CSV-FILES.png b/addons/ks_dashboard_ninja/static/description/img/Create-Charts-From-EXCEL-AND-CSV-FILES.png deleted file mode 100644 index 3ffb512..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Create-Charts-From-EXCEL-AND-CSV-FILES.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Data-Filtration - Group-Limit-Sort-By.png b/addons/ks_dashboard_ninja/static/description/img/Data-Filtration - Group-Limit-Sort-By.png deleted file mode 100644 index 1f290c2..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Data-Filtration - Group-Limit-Sort-By.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Drill_Down_Drill_UP.gif b/addons/ks_dashboard_ninja/static/description/img/Drill_Down_Drill_UP.gif deleted file mode 100644 index 1670ee9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Drill_Down_Drill_UP.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Export-Import-Dashboards.png b/addons/ks_dashboard_ninja/static/description/img/Export-Import-Dashboards.png deleted file mode 100644 index 7e68c9f..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Export-Import-Dashboards.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Generate-with-AI.png b/addons/ks_dashboard_ninja/static/description/img/Generate-with-AI.png deleted file mode 100644 index 8fd434b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Generate-with-AI.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Ksolves.png b/addons/ks_dashboard_ninja/static/description/img/Ksolves.png deleted file mode 100644 index a01bdc8..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Ksolves.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Multi-Color-Themes.png b/addons/ks_dashboard_ninja/static/description/img/Multi-Color-Themes.png deleted file mode 100644 index 8c549d7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Multi-Color-Themes.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/Odoo-Dashboard-Items.png b/addons/ks_dashboard_ninja/static/description/img/Odoo-Dashboard-Items.png deleted file mode 100644 index baf7312..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/Odoo-Dashboard-Items.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/account.png b/addons/ks_dashboard_ninja/static/description/img/account.png deleted file mode 100644 index b11dabc..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/account.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/account2.jpg b/addons/ks_dashboard_ninja/static/description/img/account2.jpg deleted file mode 100644 index 7fdc970..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/account2.jpg and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/account3.jpg b/addons/ks_dashboard_ninja/static/description/img/account3.jpg deleted file mode 100644 index 1026ca6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/account3.jpg and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/account4.jpg b/addons/ks_dashboard_ninja/static/description/img/account4.jpg deleted file mode 100644 index 7d2ff94..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/account4.jpg and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/account5.jpg b/addons/ks_dashboard_ninja/static/description/img/account5.jpg deleted file mode 100644 index 6ae5d5e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/account5.jpg and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/footer-layout-grid.png b/addons/ks_dashboard_ninja/static/description/img/footer-layout-grid.png deleted file mode 100644 index b4c222e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/footer-layout-grid.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Authentic-MYCOMPANY-Filter.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Authentic-MYCOMPANY-Filter.png deleted file mode 100644 index 6aec70e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Authentic-MYCOMPANY-Filter.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Bookmark-Dashboard.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Bookmark-Dashboard.png deleted file mode 100644 index 2382b34..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Bookmark-Dashboard.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/DN-New-img.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/DN-New-img.png deleted file mode 100644 index b416c66..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/DN-New-img.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Dashboard.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Dashboard.png deleted file mode 100644 index 8916656..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Dashboard.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Digital-transformation-bro 1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Digital-transformation-bro 1.png deleted file mode 100644 index 232b0a0..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Digital-transformation-bro 1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Edit-Layout.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Edit-Layout.gif deleted file mode 100644 index 121f947..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Edit-Layout.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Main-Feature-new.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Main-Feature-new.png deleted file mode 100644 index 8f66035..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Main-Feature-new.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/RTL-Image.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/RTL-Image.png deleted file mode 100644 index f2cfd90..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/RTL-Image.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Responsive-Fluid-Flexible-Layout.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Responsive-Fluid-Flexible-Layout.png deleted file mode 100644 index 06e965a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Responsive-Fluid-Flexible-Layout.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Set-Targets.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Set-Targets.png deleted file mode 100644 index 968775d..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Set-Targets.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Unique-User-ID.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/Unique-User-ID.png deleted file mode 100644 index 979fc32..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/Unique-User-ID.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/activity.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/activity.png deleted file mode 100644 index 9f52f7e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/activity.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/amn-logo.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/amn-logo.svg deleted file mode 100644 index eee2dd3..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/amn-logo.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow-right.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow-right.png deleted file mode 100644 index 98ed769..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow-right.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow-right.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow-right.svg deleted file mode 100644 index cb5bdec..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow-right.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow.png deleted file mode 100644 index c788495..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/arrow.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/banner-new.mp4 b/addons/ks_dashboard_ninja/static/description/img/new-add-img/banner-new.mp4 deleted file mode 100644 index de12794..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/banner-new.mp4 and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/call.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/call.png deleted file mode 100644 index a6e4863..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/call.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/chart-radial.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/chart-radial.png deleted file mode 100644 index 37e9925..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/chart-radial.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/chart.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/chart.png deleted file mode 100644 index 4d4b687..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/chart.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/chat-with-AI.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/chat-with-AI.gif deleted file mode 100644 index 451f424..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/chat-with-AI.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/client-success.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/client-success.png deleted file mode 100644 index 36a9613..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/client-success.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/clipboard-text.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/clipboard-text.svg deleted file mode 100644 index 4614e49..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/clipboard-text.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/colorfilter.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/colorfilter.png deleted file mode 100644 index f6e34bb..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/colorfilter.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/command.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/command.png deleted file mode 100644 index 4521bd8..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/command.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/copy.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/copy.svg deleted file mode 100644 index d2b1f11..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/copy.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/cta-two.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/cta-two.svg deleted file mode 100644 index b071bb0..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/cta-two.svg +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/cuboid.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/cuboid.png deleted file mode 100644 index e4942b1..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/cuboid.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/dashboard-video.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/dashboard-video.gif deleted file mode 100644 index c568ff9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/dashboard-video.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/data-personaliation-.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/data-personaliation-.png deleted file mode 100644 index b09a975..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/data-personaliation-.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/data-personalization-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/data-personalization-2.png deleted file mode 100644 index 29a4f3c..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/data-personalization-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/diagram.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/diagram.png deleted file mode 100644 index 19c0e89..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/diagram.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/dn-description-new.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/dn-description-new.png deleted file mode 100644 index 5195fcb..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/dn-description-new.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/document-text.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/document-text.png deleted file mode 100644 index 0b63f23..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/document-text.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/down-arrow.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/down-arrow.svg deleted file mode 100644 index 3a6d9a8..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/down-arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e1.png deleted file mode 100644 index 0350ad7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e2.png deleted file mode 100644 index bf0535e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e3.png deleted file mode 100644 index bfdf845..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e4.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e4.png deleted file mode 100644 index 0fec7df..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e4.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e5.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e5.png deleted file mode 100644 index 319734b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e5.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e6.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e6.png deleted file mode 100644 index 8fa87ae..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e6.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e7.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e7.png deleted file mode 100644 index 637df24..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e7.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e8.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e8.png deleted file mode 100644 index 1b3aa41..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e8.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e9.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/e9.png deleted file mode 100644 index e73ba19..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/e9.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/edit-chart.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/edit-chart.gif deleted file mode 100644 index 5d5fc8b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/edit-chart.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/educare-(ekt).png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/educare-(ekt).png deleted file mode 100644 index b97cfe0..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/educare-(ekt).png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/equals-to.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/equals-to.png deleted file mode 100644 index 1d7e117..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/equals-to.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/excel-bg.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/excel-bg.png deleted file mode 100644 index 9121128..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/excel-bg.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/explain-ai-whole.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/explain-ai-whole.gif deleted file mode 100644 index 233f73f..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/explain-ai-whole.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/feature-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/feature-3.png deleted file mode 100644 index 8ab3cdf..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/feature-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/features-Frame.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/features-Frame.png deleted file mode 100644 index 3cadf9b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/features-Frame.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/filter.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/filter.png deleted file mode 100644 index ccf0541..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/filter.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/footer-new.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/footer-new.png deleted file mode 100644 index 97258c0..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/footer-new.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-ai-keyword.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-ai-keyword.gif deleted file mode 100644 index 9c1899c..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-ai-keyword.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-ai-modal.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-ai-modal.gif deleted file mode 100644 index 7a881c4..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-ai-modal.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-dashboard-ai.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-dashboard-ai.gif deleted file mode 100644 index 5ce07be..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/generate-dashboard-ai.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/graph.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/graph.png deleted file mode 100644 index 7b798ba..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/graph.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/internal-chat.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/internal-chat.gif deleted file mode 100644 index 3a3263c..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/internal-chat.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/latest-bg.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/latest-bg.png deleted file mode 100644 index c16f75a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/latest-bg.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-eight.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-eight.svg deleted file mode 100644 index e4e01a3..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-eight.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-eleven.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-eleven.svg deleted file mode 100644 index 475583a..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-eleven.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-five.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-five.svg deleted file mode 100644 index 33e031b..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-five.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-four.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-four.svg deleted file mode 100644 index 8b0335f..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-four.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-nine.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-nine.svg deleted file mode 100644 index 6cb5cba..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-nine.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-one.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-one.svg deleted file mode 100644 index c2f1789..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-one.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-seven.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-seven.svg deleted file mode 100644 index fdf7183..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-seven.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-six.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-six.svg deleted file mode 100644 index d2aa7da..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-six.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-ten.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-ten.svg deleted file mode 100644 index aeaf66f..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-ten.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-three.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-three.svg deleted file mode 100644 index 348060b..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-three.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-twelve.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-twelve.svg deleted file mode 100644 index 7a1f0b7..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-twelve.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-two.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-two.svg deleted file mode 100644 index 77a3467..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/layer-two.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/left-arr.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/left-arr.png deleted file mode 100644 index ce6ac2b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/left-arr.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/left-logo.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/left-logo.png deleted file mode 100644 index b21d8f7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/left-logo.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/lefty.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/lefty.png deleted file mode 100644 index 10c0fe2..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/lefty.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/lifebuoy.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/lifebuoy.png deleted file mode 100644 index 63f8c25..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/lifebuoy.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/main-screen-bg.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/main-screen-bg.png deleted file mode 100644 index 7b8079e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/main-screen-bg.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/map.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/map.png deleted file mode 100644 index 5230604..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/map.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/n2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/n2.png deleted file mode 100644 index 993ee20..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/n2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/new-chart.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/new-chart.png deleted file mode 100644 index 1432799..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/new-chart.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/new-one.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/new-one.png deleted file mode 100644 index 45d8fd5..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/new-one.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/people.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/people.png deleted file mode 100644 index a243c61..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/people.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/product-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/product-3.png deleted file mode 100644 index 48b31da..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/product-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/product-blend.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/product-blend.png deleted file mode 100644 index d7d927a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/product-blend.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/radar.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/radar.png deleted file mode 100644 index e2ebac9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/radar.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/real-time-stream.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/real-time-stream.gif deleted file mode 100644 index a34cafa..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/real-time-stream.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/right-arr.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/right-arr.png deleted file mode 100644 index 40c785b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/right-arr.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/right-logo.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/right-logo.png deleted file mode 100644 index 045609d..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/right-logo.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/righty.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/righty.png deleted file mode 100644 index d04fd50..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/righty.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-1.png deleted file mode 100644 index e933d65..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-2.png deleted file mode 100644 index f6e11d4..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-3.png deleted file mode 100644 index 2c7580f..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/slide-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/sms-notification.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/sms-notification.png deleted file mode 100644 index d434d38..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/sms-notification.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/square.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/square.png deleted file mode 100644 index 1f4fef5..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/square.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/subtitle.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/subtitle.png deleted file mode 100644 index 60cc516..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/subtitle.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/support-90.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/support-90.png deleted file mode 100644 index 989ae01..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/support-90.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/support.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/support.png deleted file mode 100644 index 2f4a8eb..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/support.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/switch-layout.gif b/addons/ks_dashboard_ninja/static/description/img/new-add-img/switch-layout.gif deleted file mode 100644 index 996e724..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/switch-layout.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/12-years.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/12-years.png deleted file mode 100644 index 0cbcd37..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/12-years.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/24-7-support.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/24-7-support.png deleted file mode 100644 index 9a0b833..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/24-7-support.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Access-Control.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Access-Control.png deleted file mode 100644 index bedb14e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Access-Control.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/CMMI.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/CMMI.png deleted file mode 100644 index ffe4394..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/CMMI.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Main-Feature-new.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Main-Feature-new.png deleted file mode 100644 index ca97481..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Main-Feature-new.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Overview.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Overview.png deleted file mode 100644 index 7414908..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/Overview.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-1.png deleted file mode 100644 index d942bb1..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-2.png deleted file mode 100644 index af1c4c3..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-3-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-3-2.png deleted file mode 100644 index 26ab862..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-3-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-3.png deleted file mode 100644 index 26ab862..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-6.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-6.png deleted file mode 100644 index 2b790ae..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-6.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-7.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-7.png deleted file mode 100644 index 66b2ed6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-7.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-8.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-8.png deleted file mode 100644 index ccc20f9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-8.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-9.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-9.png deleted file mode 100644 index 627af43..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivement-9.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivment-11.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivment-11.png deleted file mode 100644 index cddeec7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/acheivment-11.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/achievement-4.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/achievement-4.png deleted file mode 100644 index b61fa89..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/achievement-4.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/achievment-10.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/achievment-10.png deleted file mode 100644 index 6a4060a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/achievment-10.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/area.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/area.png deleted file mode 100644 index fb2bb71..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/area.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/auth.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/auth.png deleted file mode 100644 index 65843db..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/auth.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/bar-chart.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/bar-chart.png deleted file mode 100644 index 02e9484..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/bar-chart.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/bullet.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/bullet.png deleted file mode 100644 index d1b9cfc..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/bullet.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/client-retention.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/client-retention.png deleted file mode 100644 index 947ea0a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/client-retention.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-1.png deleted file mode 100644 index aa82d22..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-10.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-10.png deleted file mode 100644 index 83bc481..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-10.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-11.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-11.png deleted file mode 100644 index aa3613a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-11.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-2.png deleted file mode 100644 index e4d50b0..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-3.png deleted file mode 100644 index e472dc9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-4.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-4.png deleted file mode 100644 index 1ee62a7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-4.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-5.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-5.png deleted file mode 100644 index efc07c1..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-5.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-6.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-6.png deleted file mode 100644 index 966b450..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-6.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-7.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-7.png deleted file mode 100644 index bcfcd18..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-7.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-8.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-8.png deleted file mode 100644 index 76ffba6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-8.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-9.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-9.png deleted file mode 100644 index 59dd7f1..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/cs-9.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/data-filteration.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/data-filteration.png deleted file mode 100644 index 4c8b6a2..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/data-filteration.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/doughnut.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/doughnut.png deleted file mode 100644 index ea9ec64..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/doughnut.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/ecom-development.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/ecom-development.png deleted file mode 100644 index 6b6f237..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/ecom-development.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/expert.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/expert.png deleted file mode 100644 index 8a11953..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/expert.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-1.png deleted file mode 100644 index 74e81cd..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-11.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-11.png deleted file mode 100644 index dc20cda..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-11.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-12.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-12.png deleted file mode 100644 index 47d9867..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-12.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-13.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-13.png deleted file mode 100644 index d9a18d8..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-13.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-14.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-14.png deleted file mode 100644 index cf660cb..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-14.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-15.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-15.png deleted file mode 100644 index eb4e9fe..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-15.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-16.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-16.png deleted file mode 100644 index 48d9536..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-16.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-17.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-17.png deleted file mode 100644 index 029316a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-17.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-18.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-18.png deleted file mode 100644 index 3b070f2..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-18.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-19.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-19.png deleted file mode 100644 index 1d23e77..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-19.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-2.png deleted file mode 100644 index f706d26..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-20.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-20.png deleted file mode 100644 index 92e343a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-20.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-21.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-21.png deleted file mode 100644 index 7321766..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-21.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-22.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-22.png deleted file mode 100644 index 524ba11..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-22.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-23-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-23-2.png deleted file mode 100644 index 675d117..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-23-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-24.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-24.png deleted file mode 100644 index eaae939..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-24.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-25.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-25.png deleted file mode 100644 index c7d15ba..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-25.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-26.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-26.png deleted file mode 100644 index 541e255..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-26.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-27.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-27.png deleted file mode 100644 index d710bb8..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-27.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-28.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-28.png deleted file mode 100644 index 900bb79..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-28.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-29.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-29.png deleted file mode 100644 index f795d32..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-29.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-3.png deleted file mode 100644 index adaa4bc..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-30.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-30.png deleted file mode 100644 index 265a675..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-30.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-31.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-31.png deleted file mode 100644 index 5fad6b1..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-31.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-32.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-32.png deleted file mode 100644 index 8227ee4..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-32.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-4.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-4.png deleted file mode 100644 index 21da783..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-4.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-5.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-5.png deleted file mode 100644 index 946b545..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-5.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-6.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-6.png deleted file mode 100644 index ea54956..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-6.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-7.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-7.png deleted file mode 100644 index 0ee5754..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-7.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-8.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-8.png deleted file mode 100644 index 84b0953..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-8.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-9.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-9.png deleted file mode 100644 index eec3789..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/f-9.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/file-img.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/file-img.png deleted file mode 100644 index 59843ec..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/file-img.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/flower-chart.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/flower-chart.png deleted file mode 100644 index bd056ba..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/flower-chart.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/funnel.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/funnel.png deleted file mode 100644 index 69e5822..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/funnel.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/horizontal-bar.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/horizontal-bar.png deleted file mode 100644 index d40b2f4..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/horizontal-bar.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/icons-black-file.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/icons-black-file.png deleted file mode 100644 index 1d9f3c6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/icons-black-file.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/latest-release.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/latest-release.png deleted file mode 100644 index fa932e4..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/latest-release.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/line.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/line.png deleted file mode 100644 index a472a45..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/line.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/list-view.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/list-view.png deleted file mode 100644 index d15c0f9..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/list-view.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/main-screen-bg.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/main-screen-bg.png deleted file mode 100644 index e1eda1b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/main-screen-bg.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/map.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/map.png deleted file mode 100644 index 711fb1e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/map.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-bg-main.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-bg-main.png deleted file mode 100644 index da4442e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-bg-main.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-bg-renamed.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-bg-renamed.png deleted file mode 100644 index bf6fb0a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-bg-renamed.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-frame.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-frame.png deleted file mode 100644 index 5fb4ae7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-frame.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-1.png deleted file mode 100644 index 8cc7a01..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-2.png deleted file mode 100644 index 3459163..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-3.png deleted file mode 100644 index 2330e71..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-4.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-4.png deleted file mode 100644 index 18f2dd4..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-4.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-5.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-5.png deleted file mode 100644 index c0cc196..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-intro-5.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-theme-updated.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-theme-updated.png deleted file mode 100644 index 5449b57..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/new-theme-updated.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/nse-bse.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/nse-bse.png deleted file mode 100644 index 8e02481..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/nse-bse.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-customization.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-customization.png deleted file mode 100644 index 08e8261..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-customization.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-gold.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-gold.png deleted file mode 100644 index 0f6a724..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-gold.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-mobile.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-mobile.png deleted file mode 100644 index 7b6374c..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/odoo-mobile.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/personalization-1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/personalization-1.png deleted file mode 100644 index 25f5812..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/personalization-1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/personalization-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/personalization-2.png deleted file mode 100644 index 0e45dde..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/personalization-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/pie.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/pie.png deleted file mode 100644 index 7d8895f..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/pie.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/polar-chart.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/polar-chart.png deleted file mode 100644 index e7f94b3..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/polar-chart.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/pre-defined.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/pre-defined.png deleted file mode 100644 index 278d1a6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/pre-defined.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/radar.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/radar.png deleted file mode 100644 index 3f91697..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/radar.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/radial.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/radial.png deleted file mode 100644 index 9560e3f..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/radial.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/ratings-new.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/ratings-new.png deleted file mode 100644 index 902bb83..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/ratings-new.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s1.png deleted file mode 100644 index b3beddd..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s2.png deleted file mode 100644 index a56c6ca..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s3.png deleted file mode 100644 index 12243b7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s4.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s4.png deleted file mode 100644 index 74b514d..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s4.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s5.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s5.png deleted file mode 100644 index 6fe1cf7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s5.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s6.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s6.png deleted file mode 100644 index b7d8dc7..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s6.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s7.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s7.png deleted file mode 100644 index 62333e8..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s7.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s8.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s8.png deleted file mode 100644 index 8ff27d3..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s8.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s9.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s9.png deleted file mode 100644 index 4aa5724..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/s9.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/scatter.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/scatter.png deleted file mode 100644 index 2c3ad92..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/scatter.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-1.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-1.png deleted file mode 100644 index a6fe7d6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-10.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-10.png deleted file mode 100644 index 2a869ad..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-10.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-11.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-11.png deleted file mode 100644 index 6821f2a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-11.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-2.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-2.png deleted file mode 100644 index 0344c0f..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-3.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-3.png deleted file mode 100644 index f8fb38b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-4.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-4.png deleted file mode 100644 index 3b3292a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-4.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-5.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-5.png deleted file mode 100644 index 222f82e..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-5.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-6.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-6.png deleted file mode 100644 index 1f4123d..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-6.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-7.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-7.png deleted file mode 100644 index 18ccac3..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-7.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-9.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-9.png deleted file mode 100644 index f6cd403..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/suggest-9.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/tile.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/tile.png deleted file mode 100644 index 1c00cde..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/tile.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/to-do.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/to-do.png deleted file mode 100644 index 617b535..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/to-do.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/view-ash.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/view-ash.png deleted file mode 100644 index 1f5a8c6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/view-ash.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/view-dashboard.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/view-dashboard.png deleted file mode 100644 index 1f5a8c6..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/tinified/view-dashboard.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/unique.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/unique.png deleted file mode 100644 index b4a30ab..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/unique.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/video-circle.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/video-circle.png deleted file mode 100644 index 5e2ce16..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/video-circle.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/video-circle.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/video-circle.svg deleted file mode 100644 index eef7302..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/video-circle.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/why-ksolves-bg.png b/addons/ks_dashboard_ninja/static/description/img/new-add-img/why-ksolves-bg.png deleted file mode 100644 index 3c2047c..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/new-add-img/why-ksolves-bg.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/img/new-add-img/woocommerce-logo.svg b/addons/ks_dashboard_ninja/static/description/img/new-add-img/woocommerce-logo.svg deleted file mode 100644 index 01da506..0000000 --- a/addons/ks_dashboard_ninja/static/description/img/new-add-img/woocommerce-logo.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/description/img/suggested.png b/addons/ks_dashboard_ninja/static/description/img/suggested.png deleted file mode 100644 index 06d38b4..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/img/suggested.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/index.html b/addons/ks_dashboard_ninja/static/description/index.html deleted file mode 100644 index 2bd9c6b..0000000 --- a/addons/ks_dashboard_ninja/static/description/index.html +++ /dev/null @@ -1,13590 +0,0 @@ - - - - Odoo Dashboard Ninja | Description - - - - - - - - - - - - - - -
-
-
-
-
-
- -
-
- Dashboard
- Ninja -
-
- - - 18001210218 - -
-
-
-
- -
-
- Dashboard
- Ninja -
-
- - - - 18001210218 - -
-
-
-
-
-
- main-bg - -
-

- Dashboard Ninja - with AI -

-

- Create amazing reports with the powerful & smart Odoo - Dashboard Ninja app with a
- refreshed, modern user interface for effortless navigation - and enhanced user
- experience. Enjoy the simplified workflow that makes - everything easy, from
- generating dashboards to collaborating with your team - members. -

- -
- -
-
- ks-logo -
-
- -
- -
-
-
-
- -
-
-

- Latest Release 1.1.7 -

-

- 7th April, 2025 -

-
-
-
-
-

- What’s New in Dashboard Ninja -

-
-
-
- - -

- New Theme -

-
-
- - -

- Extract Chart Insights with AI -

-
-
- - -

- Bookmark Dashboard -

-
-
- - -

- Internal Chat -

-
-
- - -

- Dashboard Overview -

-
-
- -

- Chart Visualization -

-
-
-
-
-
-
-
-
- Tailored Dashboards for Every Industry Nee -
-

- Empower your business with Odoo Best Dashboard -
- tools—customized, insightful, and ready to scale. -

-
-
-
-
-
- -
-
- Retail & E-commerce -
-
-
    -
  • - Track sales with Sales Dashboard and revenue trends. -
  • -
  • Monitor stock using Inventory Dashboard.
  • -
  • Analyze customer data via Analytic Dashboard.
  • -
  • - Create Multiple Dashboards for stores and channels. -
  • -
-
-
- -
-
-
-
- -
-
- Manufacturing -
-
-
    -
  • Measure production KPIs in an Advance Dashboard.
  • -
  • Manage stock with Accounting Stock Dashboard.
  • -
  • Analyze defects via Chart Graphs Table View.
  • -
  • - Use a Customized Robust Dashboard for supply chain - tracking. -
  • -
-
-
- -
-
-
-
- -
-
- Healthcare -
-
-
    -
  • - Visualize appointments using a Beautiful Dashboard. -
  • -
  • - Monitor medical inventory with Inventory Dashboard. -
  • -
  • Track billing via Invoice Dashboard.
  • -
  • Manage staff through a Modern Dashboard.
  • -
-
-
- -
-
-
-
- -
-
- Finance & Banking -
-
-
    -
  • View financials in an Account Dashboard.
  • -
  • Track invoices through an Invoice Dashboard.
  • -
  • Monitor ROI with Odoo Best Dashboard.
  • -
  • Build Pre-Configured Dashboards for audits.
  • -
-
-
- -
-
-
-
- -
-
- Education & EdTech -
-
-
    -
  • Review student data with an Analytic Dashboard.
  • -
  • Track attendance in a Predefined Dashboard.
  • -
  • Analyze leads via CRM Dashboard.
  • -
  • - Use a Beautiful Powerful Dashboard for faculty KPIs. -
  • -
-
-
- -
-
-
-
- -
-
- Real Estate -
-
-
    -
  • Analyze leads using Odoo Dashboard.
  • -
  • Track visits in a Best Ninja Dashboard.
  • -
  • Use Beautiful Dashboards for sales insights.
  • -
  • Create a Dashboard Studio for agents.
  • -
-
-
- -
-
-
-
- -
-
- Logistics & Transportation -
-
-
    -
  • Track delivery with a Dynamic Dashboard.
  • -
  • Monitor routes via Chart Graphs Table View.
  • -
  • View fuel data in a Robust Dashboard.
  • -
  • Combine KPIs using Multiple Dashboards.
  • -
-
-
- -
-
-
-
- -
-
- Hospitality & Travel -
-
-
    -
  • Track bookings using CRM Dashboard.
  • -
  • Analyze revenue via a Sales Dashboard.
  • -
  • Monitor campaigns in a Revamp Dashboard.
  • -
  • Build a Customized Dashboard per property.
  • -
-
-
- -
-
-
-
- -
-
- IT & SaaS -
-
-
    -
  • Track sprints in an Advance Dashboard.
  • -
  • Monitor users via Analytic Dashboard.
  • -
  • View support KPIs with Odoo Studio.
  • -
  • Build an All-In-One Dynamic Dashboard.
  • -
-
-
- -
-
-
-
- -
-
- NGOs & Non-Profits -
-
-
    -
  • View donations in a Predefined Dashboard.
  • -
  • - Track volunteers through a Customized Robust Dashboard. -
  • -
  • Analyze campaigns using a Pie Chart Dashboard.
  • -
  • - Share results with a Beautiful Powerful Dashboard. -
  • -
-
-
- -
-
-
-
- -
-
- Media & Entertainment -
-
-
    -
  • - Manage content pipelines with a Dynamic Dashboard. -
  • -
  • Track ad revenue using Sales Dashboard.
  • -
  • Monitor user engagement with Analytic Dashboards.
  • -
  • - Build Customized Dashboards for streaming, publishing, - or events. -
  • -
-
-
- -
-
-
-
- -
-
- Legal & Compliance -
-
-
    -
  • Track case progress with a Modern Dashboard.
  • -
  • Monitor billable hours via Invoice Dashboard.
  • -
  • - Manage documentation through a Predefined Dashboard. -
  • -
  • - Ensure regulatory compliance using a Customized Robust - Dashboard. -
  • -
-
-
-
- - -
- -
-
-

- Ksolves - Your
one-stop - solution -

-

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

- -
-
-
- -
-
-
-
- -
-
-

- Dashboard Ninja - Charts -

-

- 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) -

- -
-
- -
-
-
-
- -
- -
-
-
- Tiles -
-
- feature-1 -
-

- Display key performance indicators (KIPs) in small - square-shaped visualizations for a quick glance -

-
-
- -
-
-
- Line Chart -
-
- feature-2 -
-

- Visualize data trends, changes, or relationships - over time by connecting data points with straight - lines. -

-
-
- -
-
-
- List View -
-
- feature-3 -
-

- Present detailed data in a tabular format with - rows and columns for easy sorting and comparison. -

-
-
- -
-
-
- Bar Chart -
-
- feature-4 -
-

- Visualize categorical data with rectangular - vertical bars with the height proportionate to the - value they represent. -

-
-
- -
-
-
- Horizontal Bar Chart -
-
- feature-5 -
-

- Represent categorical data with rectangular - horizontal bars, representing the difference - between data categories. -

-
-
- -
-
-
- To-do Item -
-
- feature-6 -
-

- Organize all tasks or actions that need to be - completed in the form of a checklist, ensuring - easy tracking of progress. -

-
-
- -
-
-
- Polar Area Chart -
-
- feature-7 -
-

- Represent cyclical data using radial lines - separating segments, with each segment’s area - representing its value. -

-
-
- -
-
-
- Pie Chart -
-
- feature-8 -
-

- Display your data in a circular graph, with each - slice of a circle representing a fraction or - proportionate part of the whole. -

-
-
- -
-
-
- Doughnut Chart -
-
- feature-9 -
-

- Similar to a pie chart with a central hole, - providing a clean and modern look. -

-
-
- -
-
-
- Flower Chart -
-
- feature-10 -
-

- Visualize multivariate data wherein data points - are displayed as petals radiating from a central - point, with each petal’s size or color - representing its value. -

-
-
- -
-
-
- Funnel Chart -
-
- feature-11 -
-

- Visualize data as it moves through different - stages of a process with decreasing segments. - Ideal to visualize conversion rates or sales - pipelines. -

-
-
- -
-
-
- Radial Chart -
-
- feature-12 -
-

- Represent multivariate data along concentric - circles, where each circle represents a different - variable or category. -

-
-
- -
-
-
- Bullet Chart -
-
- feature-13 -
-

- A variation of a bar chart with a reference line - and markers to visualize performance against the - target or benchmark. -

-
-
- -
-
-
- Scatter Chart -
-
- feature-14 -
-

- Visualize the relationship between two continuous - variables of a data set, plotted across the X-Y - axis. -

-
-
- -
-
-
- Radar Chart -
-
- feature-15 -
-

- Display multivariate data stacked at an axis with - the same central point, resembling a spider’s web. -

-
-
- -
-
-
- Map View -
-
- feature-16 -
-

- Visualize spatial data by plotting it on a - geographical map for location-based analysis. -

-
-
- -
-
-
- Area Chart -
-
- feature-16 -
-

- Display cumulative data by filling the area - beneath the line chart, illustrating the changes - over time or the magnitude of data. -

-
-
-
-
- - -
- -
-
- -
-
-

- What makes Odoo - Dashboard Ninja Unique -

-
-
-

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

-
- -
-
- -
-
- -
- -
-
-

- Unleash the Power of AI in -
- Your - Odoo Dashboard -

-

- Generate smart, interactive charts with a single click. -

- -
-
-
- -
-
-
-
-
- - All - Features - -
- -
-
-
- -
-
- Generate Complete -
Dashboard With AI -
-
-
- -
-
-
- -
-
- Generate Items With AI -
-
-
- -
-
-
- -
-
- Generate Keyword
- Focused Dashboard
- Items With AI -
-
-
- -
-
-
- -
-
- Extract Chart Insights -
- With AI Items -
-
-
- -
-
-
- -
-
- 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 -
-
-
-
-
-
-
- -
-
-

- Revamp Your - Odoo Apps Dashboard - Like Never Before -

-

- Upgrade to a modern, intuitive, and scalable interface. -

- -
-
-
- -
-
-
-
- - -
-
-
-

- 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 -
-
-
- -
-
-
-
-
-
- why-ksolves -
- Why - Ksolves -
-

- You know us as the makers of the Odoo "Dashboard Ninja" . . -

-

- You know us as the makers of the Odoo "Dashboard Ninja" . . -

-
- -
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
- -
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
- -
-
-
-
-
-

- Client Success -

-

- Invest your trust like our elite clientele did! -

-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
-
- -
- product-blens -

- Products That Blends - Together -

-

- Related Products You May Be Interested In! -

-
-
- indicator -
-
-
-
- - - - - - - - - - -
- - - - -
- logo -
- Perfect Combo -
-
-
-
-
-
- -
- -
-
-

- Go Beyond Ordinary with -
- Ksolves Odoo Solutions -

-

- Peerless, powerful, and personalized apps to streamline - every workflow. -

- -
-
-
- -
-
-
-
-
-
-
-

- Ksolves Suggested Apps -

-

- Take a look at our other Odoo apps designed to -
- make your life easier with a smooth workflow. Don’t -
- miss the chance to uplift your Odoo ERP experience -
- with our apps! -

-
-
- -
-
-
-

- Dashboard Ninja
- Advance -

-
- -
-
-

- Dashboard Ninja Advance breaks all the limitations of - productivity by simplifying complex data into attractive - charts... -

- Learn More - arrow-right - -
-
- -
-
-
-

- List View
- Manager -

-
- -
-
-

- An app which manages the List Views on the fly and - endeavor a quick and effortless way to view/manage the - desired data, where you’ve multifarious options to... -

- Learn More - arrow-right - -
-
- -
-
-
-

- Odoo
- Wocommerce
- Connector -

-
- -
-
-

- Connect multiple WooCommerce stores to the Odoo ERP and - reach more customers with our high-end WooCommerce - Connector. -

- Learn More - arrow-right - -
-
- -
-
-
-

- Arc Backend
- Theme -

-
- -
-
-

- Bring productivity and enthusiasm into your work by - applying the Odoo Arc Backend Theme. -

- Learn More - arrow-right - -
-
- -
-
-
-

- Odoo Gantt
- View Base -

-
- -
-
-

- Gantt View Base is the fundamental framework that creates - the groundwork for using Gantt View. It works as a - prerequisite for using... -

- Learn More - arrow-right - -
-
- -
-
-
-

- Report
- Mate -

-
- -
-
-

- ReportMate extracts all the needed information for all the - fields of any Odoo Model and displays complex data in a - single view... -

- Learn More - arrow-right - -
-
- -
-
-
-

- Dynamic
- Financial
- Report -

-
- -
-
-

- With a comprehensive list of financial reports, Dynamic - Financial Report has carved out its niche among the elite - bookkeeping... -

- Learn More - arrow-right - -
-
- -
-
-
-

- Odoo Shopify
- Connector -

-
- -
-
-

- Keep hurdles away from the way of your business with a - highly effective eCommerce management solution... -

- Learn More - arrow-right - -
-
- -
-
-
-

- Access Manager
- Ninja -

-
- -
-
-

- Streamline your workflow and save valuable time and effort - by implementing Instant Access, a cutting-edge management - application... -

- Learn More - arrow-right - -
-
- -
-
-
-

- Odoo Gmail
- Connector -

-
- -
-
-

- Sync all your Google mails in your Odoo account without - any hassle by using the Ksolves Gmail Connector! This - integration allows you to manage emails... -

- Learn More - arrow-right - -
-
-
-
-
-

- Ksolves Odoo Services -

-

- Upscale your business with expert services from an Odoo Gold - Partner. -

-
-
-
- -
-
- -

- Website Application
- Development -

-
-
- -
-
- -

- Module Development -

-
-
- -
-
- -

- Theme Development -

-
-
- -
-
- -

- Implementation -

-
-
- -
-
- -

- Customization -

-
-
- -
-
- -

- Integration -

-
-
- -
-
- -

- Migration -

-
-
- -
-
- -

- Support &
- Maintenance -

-
-
- -
-
- -

- Consulting -

-
-
-
-
-
-
-
-

- What our - Clients say -

-

- Our clients love us! Hear from those who have made - data-driven decisions with Dashboard Ninja. -

-
-
-
-
-
-

- Satisfy with support -

-

- Exceptional application and outstanding customer care - indeed. My experience with them was truly remarkable, - and I highly recommend their services to anyone - looking for top-tier solutions. -

-
-
- kashif aziz -
-
- -
-
-
-
-
-
-

- Very helpful and patient -

-

- They were very easy to schedule time with and when I - got on the call, they answered all my questions. They - also understood beyond my questions and showed me some - features that would help me. -

-
-
- Ryan Felps -
-
- -
-
-
-
-
-
-
-
-
-

- Connect with us for - free demo today! -

-

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

- -
-
-
-
-
- Support -
-

- Our friendly team is here to help. -

- - support@ksolves.com -
-
-
-
-
- Sales -
-

- Questions or queries? Get in touch! -

- - sales@ksolves.com -
-
-
-
-
- Phone -
-

- Mon-Fri from 9am to 6:30pm. -

- - 18001210218 -
-
-
-
-
-
-
-
-
-
- why-ksolves -
- Dashboard Ninja - Features -
-

- Explore intuitive features that empower you to turn your - Odoo data into actionable insights. Track key performance - indicators and make informed, data-driven decisions. -

-
- -
-
-

- 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 - -
-
- -
-
-
-
- gif -
- -

- Bookmark Dashboard -

-

- Bookmark your key dashboards and easily access them for - faster data analysis. Effortlessly remove dashboards - from the bookmark when you are done with them. -

-
-
- -
-
-
- gif -
- -

- 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. -

-
-
- -
-
-
- gif -
- -

- 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 -
- -

- 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. -

-
-
-
- -
-
-
-

- Internal Chat -

-

- Collaborate with your team members with the chat feature - on every item of a dashboard. A dedicated channel is - created for conversations on each item, and all channels - are organized in a unified inbox. -

-
-
-
- gif -
-
- -
-
- gif -
-
-
-

- Switch Layout -

-

- Switch from one graph style to another with just a - single click, retaining the same data. Effortlessly - analyze your data with the desired data visualization - chart! -

-
-
-
- -
-
-

- 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 -
-
-
-
-
-
-
- gif -
- -

- Create charts From Excel & 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. -

-
-
- -
-
-
- gif -
- -

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

-

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

-
-
-
- -
-
-
-

- 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. -

-
-
-
- gif -
-
- -
-
- -
-
-
-

- 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. -

-
-
-
- -
-
-

- Generate Complete Odoo Dashboard with AI -

-

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

-
-
-
-
-
-
- gif -
-
-
-
-
-
- gif -
-
-
-
-
-
- -
-
-

- 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. -

-
-
-
- gif -
-
-
- -
-
-

- 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. -

-
-
-
-
- -
- -
-
-
- -
-
-
-
- gif -
- -

- 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. -

-
-
- -
-
-
- gif -
- -

- Authentic %MYCOMPANY Filter -

-

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

-
-
- -
-
-
- gif -
- -

- Unique User ID (%UID) -

-

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

-
-
- -
-
-
- gif -
- -

- 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. -

-
-
-
- -
-
-

- 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. -

-
-
-
- gif -
-
-
- -
-
-

- Multi - Color Themes -

-

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

-
-
-
- gif -
-
-
- -
-
-

- Dashboard Personalization/Configuration -

-

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

-
-
-
-
-
-
- gif -
-
-
-
-
-
- gif -
-
-
-
-
-
- -
-
-

- Access Control -

-

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

-
-
-
- gif -
-
-
- -
-
-

- 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. -

-
-
-
- gif -
-
-
- -
-
-

- RTL Support -

-

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

-
-
-
- -
-
-
-
-
-
-
- why-ksolves -
- Frequently Asked Questions -
-

- Sometimes you need a quick answer to your
- question. You can get it right away here. -

-
-
-
-
- - -
- -
-

- General -

-
- -
-
- To access AI features in Dashboard Ninja, go to - General Settings under the "AI API Key" section. - Enter your valid email ID and click "Get API Key". - Once verified, the key will be sent to your - registered email. -
- Fully compatible with all AI-powered features in - your Odoo Dashboard, including CRM Dashboard, - Sales Dashboard, Inventory Dashboard, and - Account Dashboard. -
-
-
- - -
-
- Dashboard Ninja with AI is an advanced Odoo - dashboard application developed by Ksolves, - empowering users to create dynamic, visually - appealing dashboards that consolidate business - data and key performance indicators. This tool - integrates artificial intelligence to automate - insights, enhance data accuracy, and optimize - business decision-making. -
-
- - -
-
- Dashboard Ninja helps businesses by providing a - single platform to visualize key metrics, track - performance in real-time, and generate actionable - insights. With AI-driven automation, businesses - can quickly identify trends, predict outcomes, and - improve operational efficiency, leading to better - decision-making and improved ROI. -
-
- - -
-
- No, Dashboard Ninja with AI is designed for users - of all technical levels. Its intuitive interface - allows you to create and customize dashboards - without any coding knowledge. -
-
- - -
-
- Yes, you can! Use the bookmark feature to save - your dashboards, making them accessible with just - a click from your bookmarks list. -
-
- - -
-
- Yes! Each dashboard item includes an internal chat - feature, allowing you to collaborate and discuss - insights directly where the data is displayed, - helping teams stay aligned in real-time. -
-
- - -
-
- Absolutely! Dashboard Ninja is mobile-responsive, - allowing you to access and interact with your - dashboards on any device. -
-
- - -
-
- Yes! Dashboard Ninja works seamlessly with both - Odoo Enterprise and Odoo Community editions. - Perfect for building Modern Dashboards like - Accounting Stock Dashboard, Invoice Dashboard, and - more. -
-
- - -
-
- Absolutely! For any custom feature or UI - enhancement in your Advance Dashboard, simply: - Email us at sales@ksolves.com Or raise a support - ticket via the Odoo App Store. Build your dream - Dashboard Studio with our expert team. -
-
- - -
-
- Yes, we offer 90 days of free support - post-purchase for any queries, issue resolution, - or basic customization. Keep your All In One - Dynamic Dashboard running smoothly with dedicated - assistance. -
-
-
-
- - -
-

- Artificial Intelligence -

-
-
- -
-
- AI in Dashboard Ninja automates data analysis - and report generation, enabling faster and more - accurate insights. It helps users uncover hidden - patterns, predict future outcomes, and - personalize dashboards to meet specific business - requirements. -
-
- - - -
-
- Yes, Dashboard Ninja with AI can automatically - assemble detailed dashboards by analyzing your - data scheme, saving time and effort in manual - configuration. -
-
- - - -
-
- By offering data-driven insights, predictive - analytics, and real-time monitoring, AI empowers - businesses to make strategic decisions based on - accurate, up-to-date information. -
-
- - - -
-
- 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. -
-
- - - -
-
- No, we never send your business data to external - AI systems. Only the table structure is securely - sent to the Ksolves AI Server. Your data stays - protected, ensuring a secure, reliable, and - AI-enhanced Dashboard experience. Ideal for - companies seeking a Customized Robust Dashboard - without compromising on security. -
-
- - - -
-
- Yes, all AI-powered features are included with - your purchase. There are no additional charges. - Make the most of your Beautiful Powerful - Dashboards using AI-driven insights. -
-
- - - -
-
- Odoo Dashboard Ninja leverages AI to streamline - the dashboard creation process. Users can input - keywords or select specific data models, and the - AI automatically generates tailored dashboard - items based on the provided information. -
-
- - - -
-
- Odoo Dashboard Ninja utilizes advanced AI - algorithms to analyze your unlabeled chart data - and generate detailed, context-rich - explanations. By selecting a chart, users - receive automated summaries that highlight key - trends, insights, and anomalies, making it - easier to interpret data without needing - extensive analytical skills. -
-
- - -
-
- No, this is not standard behavior. If your - layout changes on its own, it may be due to - customizations, record rules, group access - changes, or third-party themes/addons. -
- Please contact us at support@ksolves.com for - expert support. We’ll diagnose and restore your - Odoo Best Dashboard functionality. -
-
-
-
-
- -
-

- Charts -

-
-
- -
-
- Dashboard Ninja offers 18 visualization options, - including bar charts, pie charts, line graphs, - and more, allowing you to design interactive and - visually appealing dashboards, tiles, line - charts, list views, bar charts, horizontal - charts, to-do items, polar area charts, pie - charts, and doughnut charts. -
-
- - - -
-
- Yes, Dashboard Ninja with AI includes dynamic - and animated reporting options to enhance the - presentation of your data and make it more - engaging. -
-
- - - -
-
- Yes, you can! Hover over the item and click the - copy icon, or use the edit icon to access the - Actions dropdown, where you can move or - duplicate it. Effortlessly manage Chart Graphs - Table View across Multiple Dashboards. -
-
- - - -
-
- Absolutely. You can customize chart appearance; - we provide 4 color themes and a color palette to - fit your user interface. We also provide - multiple layouts and icons for tiles to - highlight specific data points for better visual - storytelling. -
-
- - - -
-
- Switching graph styles in Odoo Dashboard Ninja - is straightforward! First, access the dashboard - item you want to modify. Click on it to reveal - the layout options or settings icon. From there, - you’ll see a list of available graph styles—such - as bar charts, line graphs, or pie charts. - Simply click on your preferred style, and the - item will update instantly. This allows you to - customize your data visualization quickly and - efficiently without any hassle! -
-
- - - -
-
- Click the Edit Layout icon on the top left - corner. Hover over any tile or chart and use the - resize icon at the bottom-right to expand it. - Great for emphasizing key KPIs on your Dashboard - or Best Ninja Dashboard. -
-
- - - -
-
- Odoo Dashboard Ninja leverages AI to streamline - the dashboard creation process. Users can input - keywords or select specific data models, and the - AI automatically generates tailored dashboard - items based on the provided information. -
-
- - - -
-
- Odoo Dashboard Ninja utilizes advanced AI - algorithms to analyze your unlabeled chart data - and generate detailed, context-rich - explanations. By selecting a chart, users - receive automated summaries that highlight key - trends, insights, and anomalies, making it - easier to interpret data without needing - extensive analytical skills. -
-
-
-
-
- -
-

- Data Sources -

-
-
- -
-
- Dashboard Ninja supports data from within the - Odoo database, as well as from Excel and CSV - files. -
-
- - - -
-
- Yes, Dashboard Ninja provides real-time - streaming dashboards that allow you to monitor - live data feeds and get immediate insights into - current business activities. -
-
- - - -
-
- Yes, we have provided a feature to move and - duplicate any item from the platform. It offers - multi-company support, making it easy to - visualize data from different companies, - ensuring accurate and relevant reporting. -
-
-
-
-
- -
-

- Filters & Group By -

-
-
- -
-
- Dashboard Ninja offers advanced date filters, - predefined filters, and custom filter options to - help you organize and refine your data displays - based on your business needs. -
-
- - - -
-
- Yes, you can group data by categories such as - time periods, customer segments, or product - types, providing deeper insights into business - performance. -
-
- - - -
-
- Yes, with the advanced date filter, you can - generate precise reports by sorting data within - customized timeframes, such as by day, week, - quarter, or year. -
-
-
-
-
- -
-

- Access Rights -

-
-
- -
-
- Dashboard Ninja provides granular access control - features, allowing you to manage user - permissions for viewing or editing dashboards. - There are three access levels in Dashboard - Ninja: first is admin access with full dashboard - access; the second allows users to access all - charts but not configuration level access; and - the third grants access to only specific charts - in a dashboard. -
-
- - - - -
-
- Yes, with the unique User-ID (%UID) feature, you - can create personalized dashboard experiences - tailored to individual users’ preferences, - ensuring they see only the data relevant to - their roles. -
-
- - - - -
-
- Yes, you can export and import dashboards to - share across teams or instances. This feature - simplifies collaboration and allows for easy - backup of critical dashboards. -
-
- - -
-
-
    -
  • - Yes. After you create a dashboard, an action - is generated with the name: Menu Name + - “Action”. -
  • -
  • - For example, if you create a Project - Dashboard, go to User Preferences → Home - Action and select “Project Dashboard - Action”. -
  • -
  • - Easily assign Predefined Dashboards as the - default landing view for users. -
  • -
-
-
- -
-
-
-
-
-
-
-
-
-
- why-ksolves -
- Dashboard Ninja Releases -
-

- Every update brings new capabilities. Keep track of the latest - features and
- enhancements designed to visualize and analyze your data like - a pro. -

-
-
-
-
-
-
-
-
- Fixes -
-
-
-
-
-
-
- img -
-
-
-
- Latest Release 1.1.7 - (7th April, 2025) -
-
    -
  • - Fixed bugs regarding the Sub Group By & Sort By - Field and kpi. -
  • -
  • Fixed bugs regarding the Data Calculation Type.
  • -
-
-
-
-
-
-
-
-
-
- Fixes -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.1.6 - (3rd April, 2025) -
-
    -
  • - Fixes: Fixed bugs regarding the list views and kpi. -
  • -
-
-
-
-
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.1.5 - (04th March, 2025) -
-
    -
  • - Improved chart interaction: Clicking on a chart with a - sub-group applied now displays only the relevant - sub-group data. -
  • -
-
-
-
-
-
-
-
-
-
- New Feature -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.1.4 - (14th February, 2025) -
-
    -
  • New Chart Filter Feature.
  • -
-
-
-
-
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.1.3 - (10th February, 2025) -
-
    -
  • - Code restructured based on owl components and code - break fixes. -
  • -
-
-
-
-
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.1.2 - (03rd February, 2025) -
-
    -
  • - Fixed the issue when creating charts with Excel and - CSV. -
  • -
-
-
-
- -
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.1.1 - (30th January, 2025) -
-
    -
  • Bug Fix in Sorting of list charts.
  • -
-
-
-
-
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.1.0 - (23rd January, 2025) -
-
    -
  • Filters optimisation and bug fixes.
  • -
-
-
-
-
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.9 - (14th January, 2025) -
-
    -
  • Removed the warnings from logs.
  • -
-
-
-
-
-
-
-
-
-
- Fix -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.8 - (6th January, 2025) -
-
    -
  • - Improved the Dashboard Ninja compatibility with ARC - theme -
  • -
-
-
-
-
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.7 - (31st December, 2024) -
-
    -
  • - Improved the Dashboard Ninja compatibility with ARC - theme -
  • -
-
-
-
- -
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.6 - (26th December, 2024) -
-
    -
  • Updated the AI server url
  • -
-
-
-
- -
-
-
-
-
-
- Fix -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.5 - (17th December, 2024) -
-
    -
  • - Fixed the code break when changing the dashboard data. -
  • -
-
-
-
- -
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.4 - (14th December, 2024) -
-
    -
  • Client action removed.
  • -
-
-
-
-
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.3 - (12th December, 2024) -
-
    -
  • New theme navbar removed.
  • -
-
-
-
-
-
-
-
-
-
- Fix -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.2 - (09th December, 2024) -
-
    -
  • - Resolved the x-axis label formatting issue in the bar - chart when grouping by a datetime field with subgroup. -
  • -
-
-
-
- -
-
-
-
-
-
- Improvements -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.1 - (03rd December, 2024) -
-
    -
  • Bug Fixes and Improvements in UI.
  • -
-
-
-
- -
-
-
-
-
-
- New Version -
-
-
-
-
-
-
- img -
-
-
-
- Release 1.0.0 - (21st October, 2024) -
-
    -
  • - Latest Version 18 Release of Dashboard Ninja With AI. -
  • -
-
-
-
-
-
-
-
-
-
-
-
- bg-img -
-
-

- Try Dashboard Ninja
- with AI today -

- - -
-
-
-
-
-
-
-
- - - - - \ No newline at end of file diff --git a/addons/ks_dashboard_ninja/static/description/js/bootstrap.bundle.min.js b/addons/ks_dashboard_ninja/static/description/js/bootstrap.bundle.min.js deleted file mode 100644 index 3af2dc3..0000000 --- a/addons/ks_dashboard_ninja/static/description/js/bootstrap.bundle.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * 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/addons/ks_dashboard_ninja/static/description/js/jquery.slim.min.js b/addons/ks_dashboard_ninja/static/description/js/jquery.slim.min.js deleted file mode 100644 index 36b4e1a..0000000 --- a/addons/ks_dashboard_ninja/static/description/js/jquery.slim.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! 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/addons/ks_dashboard_ninja/static/description/output.gif b/addons/ks_dashboard_ninja/static/description/output.gif deleted file mode 100644 index 2f06181..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/output.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/templates/ks_account_template.png b/addons/ks_dashboard_ninja/static/description/templates/ks_account_template.png deleted file mode 100644 index b2a499b..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/templates/ks_account_template.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/templates/ks_crm_template.png b/addons/ks_dashboard_ninja/static/description/templates/ks_crm_template.png deleted file mode 100644 index 12bad29..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/templates/ks_crm_template.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/templates/ks_inventory_template.png b/addons/ks_dashboard_ninja/static/description/templates/ks_inventory_template.png deleted file mode 100644 index 90c5742..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/templates/ks_inventory_template.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/templates/ks_sale_template.png b/addons/ks_dashboard_ninja/static/description/templates/ks_sale_template.png deleted file mode 100644 index 897387a..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/templates/ks_sale_template.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/templates/ks_template1.png b/addons/ks_dashboard_ninja/static/description/templates/ks_template1.png deleted file mode 100644 index b1019bf..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/templates/ks_template1.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/templates/ks_template2.png b/addons/ks_dashboard_ninja/static/description/templates/ks_template2.png deleted file mode 100644 index aa546a2..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/templates/ks_template2.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/description/templates/ks_template3.png b/addons/ks_dashboard_ninja/static/description/templates/ks_template3.png deleted file mode 100644 index 7d23920..0000000 Binary files a/addons/ks_dashboard_ninja/static/description/templates/ks_template3.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/images/3dcube.svg b/addons/ks_dashboard_ninja/static/images/3dcube.svg deleted file mode 100644 index 1189d7f..0000000 --- a/addons/ks_dashboard_ninja/static/images/3dcube.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Area.svg b/addons/ks_dashboard_ninja/static/images/Area.svg deleted file mode 100644 index 0559bb2..0000000 --- a/addons/ks_dashboard_ninja/static/images/Area.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Bar.svg b/addons/ks_dashboard_ninja/static/images/Bar.svg deleted file mode 100644 index e92eb29..0000000 --- a/addons/ks_dashboard_ninja/static/images/Bar.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Bullet.svg b/addons/ks_dashboard_ninja/static/images/Bullet.svg deleted file mode 100644 index cb267b1..0000000 --- a/addons/ks_dashboard_ninja/static/images/Bullet.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Chatbot.svg b/addons/ks_dashboard_ninja/static/images/Chatbot.svg deleted file mode 100644 index 602abb0..0000000 --- a/addons/ks_dashboard_ninja/static/images/Chatbot.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Comp.gif b/addons/ks_dashboard_ninja/static/images/Comp.gif deleted file mode 100644 index 946577b..0000000 Binary files a/addons/ks_dashboard_ninja/static/images/Comp.gif and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/images/Doughnut.svg b/addons/ks_dashboard_ninja/static/images/Doughnut.svg deleted file mode 100644 index 424afc9..0000000 --- a/addons/ks_dashboard_ninja/static/images/Doughnut.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/Flower.svg b/addons/ks_dashboard_ninja/static/images/Flower.svg deleted file mode 100644 index 2493475..0000000 --- a/addons/ks_dashboard_ninja/static/images/Flower.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Funnel.svg b/addons/ks_dashboard_ninja/static/images/Funnel.svg deleted file mode 100644 index 95c7563..0000000 --- a/addons/ks_dashboard_ninja/static/images/Funnel.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/Horizontal Bar.svg b/addons/ks_dashboard_ninja/static/images/Horizontal Bar.svg deleted file mode 100644 index 196f565..0000000 --- a/addons/ks_dashboard_ninja/static/images/Horizontal Bar.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/KPI.svg b/addons/ks_dashboard_ninja/static/images/KPI.svg deleted file mode 100644 index 488d791..0000000 --- a/addons/ks_dashboard_ninja/static/images/KPI.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Line.svg b/addons/ks_dashboard_ninja/static/images/Line.svg deleted file mode 100644 index 8c506c8..0000000 --- a/addons/ks_dashboard_ninja/static/images/Line.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/images/List.svg b/addons/ks_dashboard_ninja/static/images/List.svg deleted file mode 100644 index 2eb3523..0000000 --- a/addons/ks_dashboard_ninja/static/images/List.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Map.svg b/addons/ks_dashboard_ninja/static/images/Map.svg deleted file mode 100644 index dffd76b..0000000 --- a/addons/ks_dashboard_ninja/static/images/Map.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Pie.svg b/addons/ks_dashboard_ninja/static/images/Pie.svg deleted file mode 100644 index 711c21b..0000000 --- a/addons/ks_dashboard_ninja/static/images/Pie.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Polar.svg b/addons/ks_dashboard_ninja/static/images/Polar.svg deleted file mode 100644 index 7606d26..0000000 --- a/addons/ks_dashboard_ninja/static/images/Polar.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/Radar.svg b/addons/ks_dashboard_ninja/static/images/Radar.svg deleted file mode 100644 index c88b70e..0000000 --- a/addons/ks_dashboard_ninja/static/images/Radar.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/Radial.svg b/addons/ks_dashboard_ninja/static/images/Radial.svg deleted file mode 100644 index 2ac7a50..0000000 --- a/addons/ks_dashboard_ninja/static/images/Radial.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Scatter.svg b/addons/ks_dashboard_ninja/static/images/Scatter.svg deleted file mode 100644 index 578e4a0..0000000 --- a/addons/ks_dashboard_ninja/static/images/Scatter.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/Tile.svg b/addons/ks_dashboard_ninja/static/images/Tile.svg deleted file mode 100644 index a595c0b..0000000 --- a/addons/ks_dashboard_ninja/static/images/Tile.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/To-do.svg b/addons/ks_dashboard_ninja/static/images/To-do.svg deleted file mode 100644 index e2864e0..0000000 --- a/addons/ks_dashboard_ninja/static/images/To-do.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/ai-icon.png b/addons/ks_dashboard_ninja/static/images/ai-icon.png deleted file mode 100644 index eb14f96..0000000 Binary files a/addons/ks_dashboard_ninja/static/images/ai-icon.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/images/area-chart.svg b/addons/ks_dashboard_ninja/static/images/area-chart.svg deleted file mode 100644 index 9d99222..0000000 --- a/addons/ks_dashboard_ninja/static/images/area-chart.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/images/bar-chart.svg b/addons/ks_dashboard_ninja/static/images/bar-chart.svg deleted file mode 100644 index a9223f2..0000000 --- a/addons/ks_dashboard_ninja/static/images/bar-chart.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Active Users.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/Active Users.svg deleted file mode 100644 index 2dd5370..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Active Users.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Charts.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Charts.svg deleted file mode 100644 index 05c7dac..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Charts.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Dashboards.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Dashboards.svg deleted file mode 100644 index 48d58c0..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Dashboards.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Lists.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Lists.svg deleted file mode 100644 index 89d853b..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/All Lists.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/ArrowRise.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/ArrowRise.svg deleted file mode 100644 index 8cf83d1..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/ArrowRise.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Bookmarked Dashboards.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/Bookmarked Dashboards.svg deleted file mode 100644 index 5754ac4..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Bookmarked Dashboards.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Graph 1.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/Graph 1.svg deleted file mode 100644 index 2b9a491..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Graph 1.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Sales-Icon.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/Sales-Icon.svg deleted file mode 100644 index aacfad5..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Sales-Icon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Total Maps.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/Total Maps.svg deleted file mode 100644 index 3dd02f1..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Total Maps.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Union.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/Union.svg deleted file mode 100644 index a9b665d..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/Union.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/access-error.png b/addons/ks_dashboard_ninja/static/images/dashboardOverview/access-error.png deleted file mode 100644 index 98157cf..0000000 Binary files a/addons/ks_dashboard_ninja/static/images/dashboardOverview/access-error.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/add-btn.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/add-btn.svg deleted file mode 100644 index cd6ea23..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/add-btn.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/add-square.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/add-square.svg deleted file mode 100644 index 0c071eb..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/add-square.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/add.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/add.svg deleted file mode 100644 index 404d324..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/add.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/arrow-right.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/arrow-right.svg deleted file mode 100644 index 20806a1..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/arrow-right.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/bookmarks.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/bookmarks.svg deleted file mode 100644 index dc9511f..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/bookmarks.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/box.png b/addons/ks_dashboard_ninja/static/images/dashboardOverview/box.png deleted file mode 100644 index 1c99ccc..0000000 Binary files a/addons/ks_dashboard_ninja/static/images/dashboardOverview/box.png and /dev/null differ diff --git a/addons/ks_dashboard_ninja/static/images/dashboardOverview/box.svg b/addons/ks_dashboard_ninja/static/images/dashboardOverview/box.svg deleted file mode 100644 index 4b1c3c8..0000000 --- a/addons/ks_dashboard_ninja/static/images/dashboardOverview/box.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - -