上传修改后的主题

This commit is contained in:
WEB许何哲\xuhez
2023-07-14 09:21:21 +08:00
parent 1c022711a1
commit a48c8b2baa
209 changed files with 18379 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

8
spiffy_theme_backend/.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/spiffy_theme_backend.iml" filepath="$PROJECT_DIR$/.idea/spiffy_theme_backend.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details
from . import models
from . import controllers

View File

@@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
# Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details
{
'name': 'Spiffy Backend Theme',
'category': 'Themes/Backend',
'version': '2.0',
'author': 'Bizople Solutions Pvt. Ltd.',
'website': 'https://www.bizople.com/',
'summary': 'The ultimate Odoo Backend theme with the most advanced key features of all time. Get your own personalized view while working on the Backend system with a wide range of choices. Spiffy theme has 3 in 1 Theme Style, Progressive Web App, Fully Responsive for all apps, Configurable Apps Icon, App Drawer with global search, RTL & Multi-Language Support, and many other key features.',
'description': """ The ultimate Odoo Backend theme with the most advanced key features of all time. Get your own personalized view while working on the Backend system with a wide range of choices. Spiffy theme has 3 in 1 Theme Style, Progressive Web App, Fully Responsive for all apps, Configurable Apps Icon, App Drawer with global search, RTL & Multi-Language Support, and many other key features. """,
'depends': ['web', 'base_setup', 'portal', 'resource'],
'data': [
'security/ir.model.access.csv',
'data/backend_config_data.xml',
'data/global_level_config.xml',
'views/manifest.xml',
'views/pwa_offline.xml',
'views/backend_configurator_view.xml',
'views/res_users_view.xml',
'views/ir_module_view.xml',
'views/pwa_shortcuts_view.xml',
'views/res_config_setting.xml',
'views/menuitems.xml',
'views/backend_configurator_template.xml',
'views/login_page_style.xml',
'views/templates_inherit.xml',
'views/to_do_list_template.xml',
],
'demo': [
'data/spiffy_default_images.xml',
],
'assets': {
'web.assets_backend': [
# Qweb files
'/spiffy_theme_backend/static/src/xml/web_inherit.xml',
'/spiffy_theme_backend/static/src/xml/menu.xml',
'/spiffy_theme_backend/static/src/xml/bookmark.xml',
'/spiffy_theme_backend/static/src/xml/base.xml',
'/spiffy_theme_backend/static/src/xml/view_button_icons.xml',
'/spiffy_theme_backend/static/src/xml/list_renderer.xml',
'/spiffy_theme_backend/static/src/xml/form_statusbar.xml',
'/spiffy_theme_backend/static/src/js/widgets/spiffyDocumentViewer.xml',
# scss files
"/spiffy_theme_backend/static/src/scss/custom_varibles.scss",
"/spiffy_theme_backend/static/src/scss/font_icons.scss",
"/spiffy_theme_backend/static/src/scss/font-family.scss",
"/spiffy_theme_backend/static/src/scss/modal.scss",
"/spiffy_theme_backend/static/src/scss/search_modal.scss",
"/spiffy_theme_backend/static/src/scss/chat_window.scss",
"/spiffy_theme_backend/static/src/scss/common_view.scss",
"/spiffy_theme_backend/static/src/scss/discuss_style.scss",
"/spiffy_theme_backend/static/src/scss/list_view.scss",
"/spiffy_theme_backend/static/src/scss/kanban_view.scss",
"/spiffy_theme_backend/static/src/scss/form_view.scss",
"/spiffy_theme_backend/static/src/scss/form_chatter.scss",
"/spiffy_theme_backend/static/src/scss/tree_form_split_view.scss",
"/spiffy_theme_backend/static/src/scss/activity_view.scss",
"/spiffy_theme_backend/static/src/scss/pivot_view.scss",
"/spiffy_theme_backend/static/src/scss/graph_view.scss",
"/spiffy_theme_backend/static/src/scss/dashboards.scss",
"/spiffy_theme_backend/static/src/scss/calendear_view.scss",
"/spiffy_theme_backend/static/src/scss/setting_page.scss",
"/spiffy_theme_backend/static/src/scss/tab_styles.scss",
"/spiffy_theme_backend/static/src/scss/popup_styles.scss",
"/spiffy_theme_backend/static/src/scss/checkbox_styles.scss",
"/spiffy_theme_backend/static/src/scss/radio_styles.scss",
"/spiffy_theme_backend/static/src/scss/separator_styles.scss",
"/spiffy_theme_backend/static/src/scss/search_panel.scss",
"/spiffy_theme_backend/static/src/scss/loader.scss",
"/spiffy_theme_backend/static/src/scss/appdrawer.scss",
"/spiffy_theme_backend/static/src/scss/bookmarks.scss",
"/spiffy_theme_backend/static/src/scss/controlpannel.scss",
"/spiffy_theme_backend/static/src/scss/side_menu.scss",
"/spiffy_theme_backend/static/src/scss/responsive.scss",
"/spiffy_theme_backend/static/src/scss/notification.scss",
"/spiffy_theme_backend/static/src/scss/burger_menu.scss",
"/spiffy_theme_backend/static/src/scss/datetime_pickers.scss",
"/spiffy_theme_backend/static/src/js/widgets/spiffyDocumentViewer.scss",
"/spiffy_theme_backend/static/src/scss/website_menu.scss",
"/spiffy_theme_backend/static/src/scss/multi_tab.scss",
"/spiffy_theme_backend/static/src/scss/to_do_list.scss",
# js files
'/spiffy_theme_backend/static/src/js/widgets/spiffyDocumentViewer.js',
"/spiffy_theme_backend/static/src/js/color_pallet.js",
"/spiffy_theme_backend/static/src/js/flip_min.js",
"/spiffy_theme_backend/static/src/js/menu.js",
"/spiffy_theme_backend/static/src/js/user_menu.js",
"/spiffy_theme_backend/static/src/js/apps_menu.js",
"/spiffy_theme_backend/static/src/js/SwitchCompanyMenu.js",
"/spiffy_theme_backend/static/src/js/form_view_renderer.js",
"/spiffy_theme_backend/static/src/js/form_controller.js",
"/spiffy_theme_backend/static/src/js/list_view_renderer.js",
"/spiffy_theme_backend/static/src/js/SpiffyPageTitle.js",
"/spiffy_theme_backend/static/src/js/pwebapp.js",
"/spiffy_theme_backend/static/src/js/iconpack_load.js",
"/spiffy_theme_backend/static/src/js/action_service.js",
"/spiffy_theme_backend/static/src/js/menu_service.js",
"/spiffy_theme_backend/static/src/js/dialog.js",
],
'web.assets_frontend': [
'/spiffy_theme_backend/static/src/scss/loginpage.scss',
],
},
'live_test_url': 'https://bit.ly/spiffy16',
'images': [
'static/description/spiffy_cover.png',
'static/description/spiffy_screenshot.gif',
],
'sequence': 1,
'installable': True,
'application': True,
'price': 170,
'license': 'OPL-1',
'currency': 'EUR',
}

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
from . import main
from . import pwa

View File

@@ -0,0 +1,801 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
import datetime
import pytz
from odoo import http, models, fields, api, tools,SUPERUSER_ID,_
from odoo.http import request
from odoo.addons.web.controllers.dataset import DataSet as primary_colorDataset
from ast import literal_eval
from odoo.addons.web.controllers.home import Home as WebHome
from odoo.service import security
from odoo.exceptions import AccessError
from odoo.addons.web.controllers.utils import ensure_db,is_user_internal
from odoo.models import check_method_name
import json
import operator
import re
from odoo.addons.web.controllers.export import GroupsTreeNode,ExportXlsxWriter,GroupExportXlsxWriter
from odoo.tools import pycompat
from odoo.addons.web.controllers.session import Session as WebSession
class BackendConfigration(http.Controller):
@http.route(['/color/pallet/'], type='json', auth='public')
def get_selected_pallet(self, **kw):
config_vals = {}
current_user = request.env.user
app_light_bg_image = kw.get('app_light_bg_image')
if app_light_bg_image:
if 'data:image/' in str(app_light_bg_image):
light_bg_file = str(app_light_bg_image).split(',')
app_light_bg_file_mimetype = light_bg_file[0]
app_light_bg_image = light_bg_file[1]
else:
light_bg_file = str(app_light_bg_image).split("'")
app_light_bg_image = light_bg_file[1]
else:
app_light_bg_image = False
config_vals.update({
'light_primary_bg_color': kw.get('light_primary_bg_color'),
'light_primary_text_color': kw.get('light_primary_text_color'),
'light_bg_image': app_light_bg_image,
'apply_light_bg_img': kw.get('apply_light_bg_img'),
'tree_form_split_view': kw.get('tree_form_split_view'),
'attachment_in_tree_view': kw.get('attachment_in_tree_view'),
'separator': kw.get('selected_separator'),
'tab': kw.get('selected_tab'),
'checkbox': kw.get('selected_checkbox'),
'radio': kw.get('selected_radio'),
'popup': kw.get('selected_popup'),
'use_custom_colors': kw.get('custom_color_pallet'),
'color_pallet': kw.get('selected_color_pallet'),
'appdrawer_custom_bg_color': kw.get('custom_drawer_bg'),
'appdrawer_custom_text_color': kw.get('custom_drawer_text'),
'use_custom_drawer_color': kw.get('custom_drawer_color_pallet'),
'drawer_color_pallet': kw.get('selected_drawer_color_pallet'),
'loader_style': kw.get('selected_loader'),
'font_family': kw.get('selected_fonts'),
'font_size': kw.get('selected_fontsize'),
'chatter_position': kw.get('selected_chatter_position'),
'top_menu_position': kw.get('selected_top_menu_position'),
'theme_style': kw.get('selected_theme_style'),
'list_view_density': kw.get('selected_list_view_density'),
'list_view_sticky_header': kw.get('selected_list_view_sticky_header'),
})
if current_user.backend_theme_config:
current_user.backend_theme_config.sudo().update(config_vals)
else:
backend_config_record = request.env['backend.config'].sudo().create(
config_vals)
current_user.sudo().write({
'backend_theme_config': backend_config_record.id
})
return True
@http.route(['/color/pallet/data/'], type='http', auth='public', sitemap=False)
def selected_pallet_data(self, **kw):
company = request.env.company
user = request.env.user
admin_users = request.env['res.users'].sudo().search([
('groups_id', 'in', request.env.ref('base.user_admin').id),
('backend_theme_config', '!=', False),
], order="id asc", limit=1)
admin_config = False
if admin_users:
admin_config = admin_users.backend_theme_config
if company.backend_theme_level == 'user_level':
if user.backend_theme_config:
config_vals = user.backend_theme_config
elif admin_config:
config_vals = admin_config
else:
config_vals = request.env['backend.config'].sudo().search(
[], order="id asc", limit=1)
else:
if admin_config:
config_vals = admin_config
else:
config_vals = request.env['backend.config'].sudo().search(
[], order="id asc", limit=1)
values = {}
separator_selection_dict = dict(
config_vals._fields['separator'].selection)
tab_selection_dict = dict(config_vals._fields['tab'].selection)
checkbox_selection_dict = dict(
config_vals._fields['checkbox'].selection)
radio_selection_dict = dict(config_vals._fields['radio'].selection)
popup_selection_dict = dict(config_vals._fields['popup'].selection)
light_bg_image = config_vals.light_bg_image
values.update({
'config_vals': config_vals,
'separator_selection_dict': separator_selection_dict,
'tab_selection_dict': tab_selection_dict,
'checkbox_selection_dict': checkbox_selection_dict,
'radio_selection_dict': radio_selection_dict,
'popup_selection_dict': popup_selection_dict,
'app_background_image': light_bg_image,
})
response = request.render(
"spiffy_theme_backend.template_backend_config_data", values)
return response
@http.route(['/get/model/record'], type='json', auth='public')
def get_record_data(self, **kw):
company = request.env.company
user = request.env.user
admin_group_id = request.env.ref('base.user_admin').id
is_admin = False
if admin_group_id in user.groups_id.ids:
is_admin = True
admin_users = request.env['res.users'].sudo().search([
('groups_id', 'in', request.env.ref('base.user_admin').id),
('backend_theme_config', '!=', False),
], order="id asc", limit=1)
admin_users_ids = admin_users.ids
admin_config = False
if admin_users:
admin_config = admin_users.backend_theme_config
show_edit_mode = True
for admin in admin_users:
if admin.backend_theme_config:
admin_config = admin.backend_theme_config
break
else:
continue
if company.backend_theme_level == 'user_level':
if user.backend_theme_config:
record_vals = user.backend_theme_config
elif admin_config:
record_vals = admin_config
else:
record_vals = request.env['backend.config'].sudo().search(
[], order="id asc", limit=1)
else:
if not user.id in admin_users_ids:
show_edit_mode = False
if admin_config:
record_vals = admin_config
else:
record_vals = request.env['backend.config'].sudo().search(
[], order="id asc", limit=1)
prod_obj = request.env['backend.config']
record_dict = record_vals.read(set(prod_obj._fields))
if user.dark_mode:
darkmode = "dark_mode"
else:
darkmode = False
if user.vertical_sidebar_pinned:
pinned_sidebar = "pinned"
else:
pinned_sidebar = False
if company.prevent_auto_save:
prevent_auto_save = "prevent_auto_save"
else:
prevent_auto_save = False
if user.enable_todo_list:
todo_list_enable = "enable_todo_list"
else:
todo_list_enable = False
record_val = {
'record_dict': record_dict,
'darkmode': darkmode,
'pinned_sidebar': pinned_sidebar,
'show_edit_mode': show_edit_mode,
'is_admin': is_admin,
'todo_list_enable': todo_list_enable,
'prevent_auto_save': prevent_auto_save,
}
return record_val
@http.route(['/get-favorite-apps'], type='json', auth='public')
def get_favorite_apps(self, **kw):
user_id = request.env.user
app_list = []
if user_id.app_ids:
for app in user_id.app_ids:
irmenu = request.env['ir.ui.menu'].sudo().search(
[('id', '=', app.app_id)])
if irmenu:
app_dict = {
'name': app.name,
'app_id': app.app_id,
'app_xmlid': app.app_xmlid,
'app_actionid': app.app_actionid,
'line_id': app.id,
'use_icon': irmenu.use_icon,
'icon_class_name': irmenu.icon_class_name,
'icon_img': irmenu.icon_img,
'web_icon': irmenu.web_icon,
'web_icon_data': irmenu.web_icon_data,
}
app_list.append(app_dict)
record_val = {
'app_list': app_list,
}
return record_val
else:
return False
@http.route(['/update-user-fav-apps'], type='json', auth='public')
def update_favorite_apps(self, **kw):
user_id = request.env.user
user_id.sudo().write({
'app_ids': [(0, 0, {
'name': kw.get('app_name'),
'app_id': kw.get('app_id'),
})]
})
return True
@http.route(['/remove-user-fav-apps'], type='json', auth='public')
def remove_favorite_apps(self, **kw):
user_id = request.env.user
for line in user_id.app_ids:
if line.app_id == str(kw.get('app_id')):
user_id.sudo().write({
'app_ids': [(3, line.id)]
})
return True
@http.route(['/get/active/menu'], type='json', auth='public')
def get_active_menu_data(self, **kw):
menu_items = []
menu_records = request.env['ir.ui.menu'].search(
[('parent_id', '=', False)])
for menu in menu_records:
menu_items.append({
'menu_name': menu.complete_name,
'menu_id': menu.id
})
return menu_items
@http.route(['/get/appsearch/data'], type='json', auth='public')
def get_appsearch_data(self, menuOption=None, **kw):
menu_items = []
menu_records = request.env['ir.ui.menu'].search(
[('name', 'ilike', kw.get('searchvals'))], order='id asc')
if menuOption:
for record in menu_records:
if record.parent_path:
parent_record = record.parent_path.split('/')
parent_record_id = parent_record[0]
if parent_record_id == menuOption:
if not record.child_id:
menu_items.append({
'name': record.complete_name,
'menu_id': record.id
})
else:
for record in menu_records:
if not record.child_id:
menu_items.append({
'name': record.complete_name,
'menu_id': record.id,
'previous_menu_id': record.parent_id.id,
'action_id': record.action.id if record.action else None,
})
return menu_items
@http.route(['/get/tab/title/'], type='json', auth='public')
def get_tab_title(self, **kw):
company_id = request.env.company
new_name = company_id.tab_name
return new_name
@http.route(['/get/active/lang'], type='json', auth='public')
def get_active_lang(self, **kw):
lang_records = request.env['res.lang'].sudo().search(
[('active', '=', 'True')])
lang_list = []
for lang in lang_records:
lang_list.append({
'lang_name': lang.name,
'lang_code': lang.code,
})
return lang_list
@http.route(['/change/active/lang'], type='json', auth='public')
def biz_change_active_lang(self, **kw):
request.env.user.lang = kw.get('lang')
return True
@http.route('/text_color/label_color',type="json",auth="none")
def text_color_label_color(self,**kw):
generated_file_data = ''
if 'options' in kw:
if 'file_generator' and 'options' in kw['options']:
check_method_name(kw['options']['file_generator'])
file_generator = kw['options']['file_generator']
options = json.loads(kw['options']['options'])
uid = request.uid
allowed_company_ids = [company_data['id'] for company_data in options.get('multi_company', [])]
if not allowed_company_ids:
company_str = request.httprequest.cookies.get('cids', str(request.env.user.company_id.id))
allowed_company_ids = [int(str_id) for str_id in company_str.split(',')]
report = request.env['account.report'].sudo().with_user(uid).with_context(allowed_company_ids=allowed_company_ids).browse(options['report_id'])
btn_report_data = report.dispatch_report_action(options, file_generator)
pdf_report_name = btn_report_data['file_name'].split('.')[0]
new_pdf_report_name = pdf_report_name.replace(" ","")
generated_file_data = {
'file_content':btn_report_data['file_content'],
'file_type':'.'+str(btn_report_data['file_type']),
'file_name':new_pdf_report_name
}
elif 'data' and 'context' in kw['options']:
data_context = kw['options']['context']
requestcontent = json.loads(kw['options']['data'])
data = json.loads(data_context)
context = data
url, type_ = requestcontent[0], requestcontent[1]
reportname = '???'
report = request.env['ir.actions.report']
if type_ in ['qweb-pdf', 'qweb-text']:
converter = 'pdf' if type_ == 'qweb-pdf' else 'text'
extension = '.pdf' if type_ == 'qweb-pdf' else '.txt'
pattern = '/report/pdf/' if type_ == 'qweb-pdf' else '/report/text/'
reportname = url.split(pattern)[1].split('?')[0]
docids = None
if '/' in reportname:
reportname, docids = reportname.split('/')
if docids:
docids = [int(i) for i in docids.split(',') if i.isdigit()]
report_data = report.sudo().with_context(context)._render_qweb_pdf(reportname, docids, data=data)[0]
report_obj = request.env['ir.actions.report']
filereport = report_obj.with_context(context).sudo().search([('report_name', '=', reportname)], limit=1)
# obj = request.env[filereport.model].browse(docids)
# report_name = safe_eval(filereport.print_report_name, {'object': obj, 'time': time})
file_name = filereport.name if filereport else 'Test'
pdf_report_name = file_name.replace(" ","")
new_report_name = re.sub('[/]',"",pdf_report_name)
generated_file_data = {
'file_content':report_data,
'file_type':extension,
'file_name':new_report_name
}
elif 'import_compat' in kw['options']['data']:
params = json.loads(kw['options']['data'])
model, fields, ids, domain, import_compat = \
operator.itemgetter('model', 'fields', 'ids', 'domain', 'import_compat')(params)
Model = request.env[model].sudo().with_context(import_compat=import_compat, **params.get('context', {}))
if not Model._is_an_ordinary_table():
fields = [field for field in fields if field['name'] != 'id']
field_names = [f['name'] for f in fields]
if import_compat:
columns_headers = field_names
else:
columns_headers = [val['label'].strip() for val in fields]
rows=None
groupby = params.get('groupby')
if model not in request.env:
return model
model_description = request.env['ir.model']._get(model).name
if not import_compat and groupby:
groupby_type = [Model._fields[x.split(':')[0]].type for x in groupby]
domain = [('id', 'in', ids)] if ids else domain
groups_data = Model.read_group(domain, [x if x != '.id' else 'id' for x in field_names], groupby, lazy=False)
tree = GroupsTreeNode(Model, field_names, groupby, groupby_type)
for leaf in groups_data:
tree.insert_leaf(leaf)
with GroupExportXlsxWriter(fields, tree.count) as xlsx_writer:
x, y = 1, 0
for group_name, group in tree.children.items():
x, y = xlsx_writer.write_group(x, y, group_name, group)
generated_file_data = {
'file_content':xlsx_writer.value,
'file_type':'xlsx',
'file_name':'test'}
else:
records = Model.browse(ids) if ids else Model.search(domain, offset=0, limit=False, order=False)
export_data = records.export_data(field_names).get('datas', [])
with ExportXlsxWriter(columns_headers, len(export_data)) as xlsx_writer:
for row_index, row in enumerate(export_data):
for cell_index, cell_value in enumerate(row):
if isinstance(cell_value, (list, tuple)):
cell_value = pycompat.to_text(cell_value)
xlsx_writer.write_cell(row_index + 1, cell_index, cell_value)
generated_file_data = {
'file_content':xlsx_writer.value,
'file_type':'.xlsx',
'file_name':model_description}
return generated_file_data
@http.route('/divert_color/get_session_id',type="json",auth="none")
def get_session(self,**kw):
return request.session.sid
@http.route(['/active/dark/mode'], type='json', auth='public')
def active_dark_mode(self, **kw):
dark_mode = kw.get('dark_mode')
backend_theme_config = request.env['backend.config'].sudo().search([])
user = request.env.user
if dark_mode == 'on':
user.update({
'dark_mode': True,
})
dark_mode = user.dark_mode
return dark_mode
elif dark_mode == 'off':
user.update({
'dark_mode': False,
})
dark_mode = user.dark_mode
return dark_mode
@http.route(['/sidebar/behavior/update'], type='json', auth='public')
def sidebar_behavior(self, **kw):
user = request.env.user
sidebar_pinned = kw.get('sidebar_pinned')
user.update({
'vertical_sidebar_pinned': sidebar_pinned,
})
return True
@http.route(['/get/dark/mode/data'], type='json', auth='public')
def dark_mode_on(self, **kw):
user = request.env.user
dark_mode_value = user.dark_mode
return dark_mode_value
# SPIFFY MULTI TAB START
@http.route(['/add/mutli/tab'], type='json', auth='public')
def add_multi_tab(self, **kw):
user = request.env.user
# user.sudo().write({
# 'multi_tab_ids': False,
# })
multi_tab_ids = user.multi_tab_ids.filtered(
lambda mt: mt.name == kw.get('name'))
if not multi_tab_ids:
user.sudo().write({
'multi_tab_ids': [(0, 0, {
'name': kw.get('name'),
'url': kw.get('url'),
'actionId': kw.get('actionId'),
'menuId': kw.get('menuId'),
'menu_xmlid': kw.get('menu_xmlid'),
})]
})
return True
@http.route(['/get/mutli/tab'], type='json', auth='public')
def get_multi_tab(self, **kw):
obj = request.env['biz.multi.tab']
user = request.env.user
if user.multi_tab_ids:
record_dict = user.multi_tab_ids.sudo().read(set(obj._fields))
return record_dict
else:
return False
@http.route(['/remove/multi/tab'], type='json', auth='public')
def remove_multi_tab(self, **kw):
multi_tab = request.env['biz.multi.tab'].sudo().search(
[('id', '=', kw.get('multi_tab_id'))])
multi_tab.unlink()
user = request.env.user
multi_tab_count = len(user.multi_tab_ids)
values = {
'removeTab': True,
'multi_tab_count': multi_tab_count,
}
return values
@http.route(['/update/tab/details'], type='json', auth='public')
def update_tabaction(self, **kw):
tabId = kw.get('tabId')
TabTitle = kw.get('TabTitle')
url = kw.get('url')
ActionId = kw.get('ActionId')
menu_xmlid = kw.get('menu_xmlid')
multi_tab = request.env['biz.multi.tab'].sudo().search(
[('id', '=', tabId)])
if multi_tab:
multi_tab.sudo().write({
'name': TabTitle or multi_tab.name,
'url': url or multi_tab.url,
'actionId': ActionId or multi_tab.ActionId,
'menu_xmlid': menu_xmlid or multi_tab.menu_xmlid,
})
return True
# SPIFFY MULTI TAB END
@http.route(['/add/bookmark/link'], type='json', auth='public')
def add_bookmark_link(self, **kw):
user = request.env.user
bookmark_ids = user.bookmark_ids.filtered(
lambda b: b.name == kw.get('name'))
if not bookmark_ids:
user.sudo().write({
'bookmark_ids': [(0, 0, {
'name': kw.get('name'),
'url': kw.get('url'),
'title': kw.get('title'),
})]
})
return True
@http.route(['/update/bookmark/link'], type='json', auth='public')
def update_bookmark_link(self, **kw):
bookmark = request.env['bookmark.link'].sudo().search(
[('id', '=', kw.get('bookmark_id'))])
updated_bookmark = bookmark.update({
'name': kw.get('bookmark_name'),
'title': kw.get('bookmark_title'),
})
return True
@http.route(['/remove/bookmark/link'], type='json', auth='public')
def remove_bookmark_link(self, **kw):
bookmark = request.env['bookmark.link'].sudo().search(
[('id', '=', kw.get('bookmark_id'))])
bookmark.unlink()
return True
@http.route(['/get/bookmark/link'], type='json', auth='public')
def get_bookmark_link(self, **kw):
obj = request.env['bookmark.link']
user = request.env.user
record_dict = user.bookmark_ids.sudo().read(set(obj._fields))
return record_dict
@http.route(['/get/attachment/data'], type='json', auth='public')
def get_attachment_data(self, **kw):
rec_ids = kw.get('rec_ids')
for rec in rec_ids:
if isinstance(rec, str):
rec_ids.remove(rec)
if kw.get('model') and rec_ids:
# FOR DATA SPEED ISSUE; SEARCH ATTACHMENT DATA WITH SQL QUERY
attachments = request.env['ir.attachment'].search([
('res_model', '=', kw.get('model'))
])
attachment_data = []
attachment_res_id_set = set()
for attachment in attachments:
attachment_res_id_set.add(attachment.res_id)
dict = {}
for res_id in attachment_res_id_set:
filtered_attachment_record = attachments.filtered(
lambda attachment: attachment.res_id == res_id)
for fac in filtered_attachment_record:
if dict.get(res_id):
dict[res_id].append({
'attachment_id': fac.id,
'attachment_mimetype': fac.mimetype,
'attachment_name': fac.name,
})
else:
dict[res_id] = [{
'attachment_id': fac.id,
'attachment_mimetype': fac.mimetype,
'attachment_name': fac.name,
}]
attachment_data.append(dict)
return attachment_data
@http.route(['/get/irmenu/icondata'], type='json', auth='public')
def get_irmenu_icondata(self, **kw):
irmenuobj = request.env['ir.ui.menu']
irmenu = request.env['ir.ui.menu'].sudo().search(
[('id', 'in', kw.get('menu_ids'))])
app_menu_dict = {}
for menu in irmenu:
menu_dict = menu.read(set(irmenuobj._fields))
app_menu_dict[menu.id] = menu_dict
return app_menu_dict
# TO DO LIST CONTROLLERS
@http.route(['/show/user/todo/list/'], type='http', auth='public', sitemap=False)
def show_user_todo_list(self, **kw):
company = request.env.company
user = request.env.user
values = {}
user_tz_offset = user.tz_offset
user_tz_offset_time = datetime.datetime.strptime(user_tz_offset, '%z').utcoffset()
today_date = datetime.datetime.now()
today_date_with_offset = datetime.datetime.now() + user_tz_offset_time
values.update({
'user': user.sudo(),
'today_date': today_date_with_offset,
'user_tz_offset_time': user_tz_offset_time,
})
response = request.render("spiffy_theme_backend.to_do_list_template", values)
return response
@http.route(['/create/todo'], type='json', auth='public')
def create_todo(self, **kw):
user_id = kw.get('user_id', None)
note_title = kw.get('note_title', None)
note_description = kw.get('note_description', None)
is_update = kw.get('is_update')
note_id = kw.get('note_id', None)
note_pallet = kw.get('note_pallet', None)
user = request.env.user
if user_id and (note_title or note_description):
user_tz_offset = user.tz_offset
user_tz_offset_time = datetime.datetime.strptime(user_tz_offset, '%z')
todo_obj = request.env['todo.list'].sudo()
if is_update:
todo_record = todo_obj.browse(int(note_id))
todo_record.update({
'name': note_title,
'description': note_description,
'note_color_pallet': note_pallet,
})
else:
todo_record = todo_obj.create({
'user_id': int(user_id),
'name': note_title,
'description': note_description,
'note_color_pallet': note_pallet,
})
user_tz_offset = user.tz_offset
user_tz_offset_time = datetime.datetime.strptime(user_tz_offset, '%z').utcoffset()
today_date = datetime.datetime.now()
today_date_with_offset = datetime.datetime.now() + user_tz_offset_time
note_content = request.env['ir.ui.view']._render_template(
"spiffy_theme_backend.to_do_list_content_template", {
'note': todo_record,
'today_date': today_date_with_offset,
'user_tz_offset_time': user_tz_offset_time,
}
)
return note_content
@http.route(['/delete/todo'], type='json', auth='public')
def delete_todo(self, **kw):
note_id = kw.get('noteID', None)
if note_id:
todo_obj = request.env['todo.list'].sudo()
todo_record = todo_obj.browse(note_id)
todo_record.unlink()
return True
else:
return False
class Dataset(primary_colorDataset):
@http.route(['/web/dataset/call_kw', '/web/dataset/call_kw/<path:path>'], type='json', auth="user")
def call_kw(self, model, method, args, kwargs, path=None):
if type(args) == str:
args = literal_eval(args)
if type(kwargs) == str:
kwargs = literal_eval(kwargs)
res = super(Dataset, self).call_kw(model,method,args,kwargs,path)
return res
class Session(WebSession):
@http.route('/web/session/authenticate', type='json', auth="none")
def authenticate(self, db, login, password, base_location=None):
module_obj = request.env['ir.module.module'].sudo().search([('name','=','spiffy_theme_backend'),('state','=','installed')])
if module_obj:
if request.env.context.get('color_data'):
color_data = request.env.context.get('color_data')
color_id = request.env.context.get('color_id')
theme_color = request.env.context.get('theme_color')
view_obj = request.env['ir.ui.view'].sudo().search(['|',('key','=',color_data),('key','=',theme_color)])
if view_obj:
view_color = view_obj.arch.find(color_id)
if view_color == -1:
return {
'code':201,
'message':'Spiffy Theme is not installed in your Odoo'
}
else:
return {
'code':201,
'message':'Spiffy Theme is not installed in your Odoo'
}
else:
return {
'code':201,
'message':'Spiffy Theme is not installed in your Odoo'
}
res = super(Session, self).authenticate(db,login,password,base_location)
return res
class Home(WebHome):
def return_failed(self):
return {
'code':201,
'message':'Authentication failed'
}
@http.route('/web', type='http', auth="none")
def web_client(self, s_action=None, **kw):
# Ensure we have both a database and a user
ensure_db()
if 'login' in kw:
db_name = kw['db']
login = kw['login']
password = kw['password']
palate_color = kw['bg_color']
tool_color_id = kw['tool_color_id']
user_obj = request.env['res.users']
user = user_obj.search(user_obj._get_login_domain(login), order=user_obj._get_login_order(), limit=1)
try:
web_session = request.session.authenticate(db_name,login,password)
except:
self.return_failed()
if palate_color:
request.env.user.table_color = True
else:
request.env.user.table_color = False
if tool_color_id:
request.env.user.tool_color_id = tool_color_id
if 'bg_color' in kw:
request.env.user.table_color = True
if 'tool_color_id' in kw:
request.env.user.table_color = True
if not request.session.uid:
return request.redirect('/web/login', 303)
if kw.get('redirect'):
return request.redirect(kw.get('redirect'), 303)
if not security.check_session(request.session, request.env):
raise http.SessionExpiredException("Session expired")
if not is_user_internal(request.session.uid):
return request.redirect('/web/login_successful', 303)
# Side-effect, refresh the session lifetime
request.session.touch()
# Restore the user on the environment, it was lost due to auth="none"
request.update_env(user=request.session.uid)
if 'bg_color' not in kw:
request.env.user.table_color = False
if 'tool_color_id' not in kw:
request.env.user.tool_color_id = False
try:
context = request.env['ir.http'].webclient_rendering_context()
response = request.render('web.webclient_bootstrap', qcontext=context)
response.headers['X-Frame-Options'] = 'DENY'
return response
except AccessError:
return request.redirect('/web/login?error=access')

View File

@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
import json
from odoo import http
from odoo.http import request
class PwaMain(http.Controller):
def get_asset_urls(self, asset_xml_id):
qweb = request.env['ir.qweb'].sudo()
assets = qweb._get_asset_nodes(asset_xml_id, {}, True, True)
urls = []
for asset in assets:
if asset[0] == 'link':
urls.append(asset[1]['href'])
if asset[0] == 'script':
urls.append(asset[1]['src'])
return urls
@http.route('/service_worker.js', type='http', auth="public", sitemap=False)
def service_worker(self):
qweb = request.env['ir.qweb'].sudo()
company_id = request.env.company.id
lang_code = request.env.lang
current_lang = request.env['res.lang']._lang_get(lang_code)
mimetype = 'text/javascript;charset=utf-8'
content = qweb._render('spiffy_theme_backend.service_worker', {
'company_id': company_id,
})
return request.make_response(content, [('Content-Type', mimetype)])
@http.route('/pwa/enabled', type='json', auth="public")
def enabled_pwa(self):
company_id = request.env.company
if company_id.enable_pwa:
return company_id.enable_pwa
else:
return False
@http.route('/pwa/offline', type='http', auth="public")
def pwa_offline(self, **kw):
return request.render('spiffy_theme_backend.pwa_offline_page',)
@http.route('/spiffy_theme_backend/<int:company_id>/manifest.json', type='http', auth="public")
def manifest(self, company_id=None):
company = request.env['res.company'].search(
[('id', '=', company_id)]) if company_id else request.env.company
pwashortlist = []
app_name_pwa = company.app_name_pwa
short_name_pwa = company.short_name_pwa
description_pwa = company.description_pwa
background_color_pwa = company.background_color_pwa
theme_color_pwa = company.theme_color_pwa
start_url_pwa = company.start_url_pwa
image_192_pwa = "/web/image/res.company/%s/image_192_pwa/192x192" % (
company.id)
image_512_pwa = "/web/image/res.company/%s/image_512_pwa/512x512" % (
company.id)
pwa_content = {
"name": app_name_pwa,
"short_name": short_name_pwa,
"icons": [{
"sizes": "192x192",
"src": image_192_pwa,
"type": "image/png"
}, {
"sizes": "512x512",
"src": image_512_pwa,
"type": "image/png"
}],
"start_url": start_url_pwa,
"display": "standalone",
"scope": "/",
"background_color": background_color_pwa,
"theme_color": theme_color_pwa,
}
if company.pwa_shortcuts_ids:
for pwashorts in company.pwa_shortcuts_ids:
dict = {
"name": pwashorts.name,
"short_name": pwashorts.short_name,
"description": pwashorts.description,
"url": pwashorts.url,
"icons": [{"src": "/web/image/res.company/%s/image_192_shortcut" % (
company.id), "sizes": "192x192"}],
}
pwashortlist.append(dict)
pwa_content.update({
"shortcuts": pwashortlist
})
return request.make_response(
data=json.dumps(pwa_content),
headers=[('Content-Type', 'application/json')]
)

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data noupdate="1">
<record id="backend_config_data" model="backend.config">
<field name="light_primary_bg_color">#0097a7</field>
<field name="light_primary_text_color">#ffffff</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="base.user_admin" model="res.users">
<field name="backend_theme_config" ref="spiffy_theme_backend.backend_config_data"></field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data noupdate="1">
<record id="spiffy_backend_theme_default_images" model="res.config.settings">
<field name="backend_menubar_logo" type="base64" file="spiffy_theme_backend/static/description/vertical-pinned-menu-logo.png" />
<field name="backend_menubar_logo_icon" type="base64" file="spiffy_theme_backend/static/description/vertical-unpinned-menu-logo.png" />
<field name="image_192_pwa" type="base64" file="spiffy_theme_backend/static/description/icon.png" />
<field name="image_512_pwa" type="base64" file="spiffy_theme_backend/static/description/icon.png" />
</record>
</data>
</odoo>

View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
from . import backend_configurator
from . import res_users
from . import res_company
from . import res_config_setting
from . import ir_menu
from . import favorite_apps
from . import bookmark
from . import multi_tab
from . import ir_http
from . import pwa_shortcuts
from . import to_do_list
from . import ir_module

View File

@@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
from odoo.modules.module import get_resource_path
from odoo import api, fields, models, tools, _
from odoo.exceptions import UserError
import base64
class BackendConfig(models.Model):
_name = 'backend.config'
_description = "Configurator Backend Theme"
def _default_app_drawer_bg_image(self):
image_path = get_resource_path(
'spiffy_theme_backend', 'static/description', 'app-drawer-bg-image.png')
with tools.file_open(image_path, 'rb') as f:
return base64.b64encode(f.read())
use_custom_colors = fields.Boolean(string="Use Custom Colors")
use_custom_drawer_color = fields.Boolean(string="Use Custom Drawer Colors")
tree_form_split_view = fields.Boolean(string="Tree Form Split View")
color_pallet = fields.Selection([
('pallet_1', 'Color Pallet 1'),
('pallet_2', 'Color Pallet 2'),
('pallet_3', 'Color Pallet 3'),
('pallet_4', 'Color Pallet 4'),
('pallet_5', 'Color Pallet 5'),
('pallet_6', 'Color Pallet 6'),
('pallet_7', 'Color Pallet 7'),
('pallet_8', 'Color Pallet 8'),
('pallet_9', 'Color Pallet 9'),
],default="pallet_9", string="Color Pallets")
drawer_color_pallet = fields.Selection([
('drawer_pallet_1', 'Color Pallet 1'),
('drawer_pallet_2', 'Color Pallet 2'),
('drawer_pallet_3', 'Color Pallet 3'),
('drawer_pallet_4', 'Color Pallet 4'),
('drawer_pallet_5', 'Color Pallet 5'),
('drawer_pallet_6', 'Color Pallet 6'),
('drawer_pallet_7', 'Color Pallet 7'),
('drawer_pallet_8', 'Color Pallet 8'),
('drawer_pallet_9', 'Color Pallet 9'),
],default="drawer_pallet_9", string="Drawer Color Pallets")
appdrawer_custom_bg_color = fields.Char(string="App Drawer Custom Background Color",default="#0097a7")
appdrawer_custom_text_color = fields.Char(string="App Drawer Custom Text Color",default="#ffffff")
light_primary_bg_color = fields.Char(string="Primary Background Color for light",default="#0097a7")
light_primary_text_color = fields.Char(string="Primary Text Color for light",default="#ffffff")
apply_light_bg_img = fields.Boolean(string="Apply light bg image")
light_bg_image = fields.Binary(string="Background Image For light", default=_default_app_drawer_bg_image, readonly=False)
dark_primary_bg_color = fields.Char(string="Primary Background Color for dark",default="#0097a7")
dark_primary_text_color = fields.Char(string="Primary Text Color for dark",default="#ffffff")
dark_secondry_bg_color = fields.Char(string="Secondry Background Color for dark",default="#242424")
dark_secondry_text_color = fields.Char(string="Secondry Text Color for dark",default="#ffffff")
dark_body_bg_color = fields.Char(string="Body Background Color for dark",default="#1d1d1d")
dark_body_text_color = fields.Char(string="Body Text Color for dark",default="#ffffff")
separator = fields.Selection([
('separator_style_1', 'Separator Style 1'),
('separator_style_2', 'Separator Style 2'),
('separator_style_3', 'Separator Style 3'),
('separator_style_4', 'Separator Style 4')],
default="separator_style_2", string="Separator Styles")
tab = fields.Selection([
('tab_style_1', 'Tab Style 1'),
('tab_style_2', 'Tab Style 2'),
('tab_style_3', 'Tab Style 3'),
('tab_style_4', 'Tab Style 4')],
default="tab_style_1", string="Tab Styles")
checkbox = fields.Selection([
('checkbox_style_1', 'Checkbox Style 1'),
('checkbox_style_2', 'Checkbox Style 2'),
('checkbox_style_3', 'Checkbox Style 3'),
('checkbox_style_4', 'Checkbox Style 4')],
default="checkbox_style_4", string="Checkbox Styles")
radio = fields.Selection([
('radio_style_1', 'Radio Style 1'),
('radio_style_2', 'Radio Style 2'),
('radio_style_3', 'Radio Style 3'),
('radio_style_4', 'Radio Style 4')],
default="radio_style_1", string="Radio Styles")
popup = fields.Selection([
('popup_style_1', 'popup Style 1'),
('popup_style_2', 'popup Style 2'),
('popup_style_3', 'popup Style 3'),
('popup_style_4', 'popup Style 4')],
default="popup_style_2", string="popup Styles")
chatter_position = fields.Selection([
('chatter_right', 'Chatter Right'),
('chatter_bottom', 'Chatter Bottom')],
default="chatter_right", string="Chatter Position")
top_menu_position = fields.Selection([
('top_menu_horizontal', 'Top Menu Horizontal'),
('top_menu_vertical', 'Top Menu Vertical')],
default="top_menu_vertical", string="Top Menu Position")
theme_style = fields.Selection([
('biz_theme_rounded', 'Rounded Theme'),
('biz_theme_standard', 'Standard Theme'),
('biz_theme_square', 'Square Theme')],
default="biz_theme_rounded", string="Theme Style")
attachment_in_tree_view = fields.Boolean(string="Show Attachement in tree view")
font_size = fields.Selection([
('font_small', 'Font Small'),
('font_medium', 'Font Medium'),
('font_large', 'Font large')],
default="font_medium", string="Font size")
loader_style = fields.Selection([
('loader_style_1', 'Loader Style 1'),
('loader_style_2', 'Loader Style 2'),
('loader_style_3', 'Loader Style 3'),
('loader_style_4', 'Loader Style 4'),
('loader_style_5', 'Loader Style 5'),
('loader_style_6', 'Loader Style 6'),
('loader_style_7', 'Loader Style 7'),
('loader_style_8', 'Loader Style 8'),
('loader_style_9', 'Loader Style 9'),
('loader_style_10', 'Loader Style 10'),],
default="loader_style_10", string="Loader Styles")
font_family = fields.Selection([
('lato', 'Lato'),
('montserrat', 'Montserrat'),
('open_sans', 'Open Sans'),
('oswald', 'Oswald'),
('raleway', 'Raleway'),
('roboto', 'Roboto'),
('poppins', 'Poppins'),
('rubik', 'Rubik'),
('inter', 'Inter'),
('josefin_sans', 'Josefin Sans'),
('varela_round', 'Varela Round'),
('manrope', 'Manrope'),
('Nunito_Sans', 'Nunito Sans')],
default="rubik", string="Font Family")
list_view_density = fields.Selection([
('list_comfortable', 'Comfortable'),
('list_compact', 'Compact'),],
default="list_comfortable", string="List View Density")
list_view_sticky_header = fields.Boolean(string="List view Sticky Header")

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# Part of Odoo Module Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api
class Bookmarklink(models.Model):
_name = 'bookmark.link'
_description = "Bookmark Link"
name = fields.Char("Name")
title = fields.Char("Title")
url = fields.Char("URL")
user_id = fields.Many2one('res.users')

View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Part of Odoo Module Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api
class FavoriteApps(models.Model):
_name = "favorite.apps"
_description = "Favorite Apps"
name = fields.Char("Name")
app_id = fields.Char("App Id")
app_xmlid = fields.Char("App XML Id")
app_actionid = fields.Char("App Action Id")
user_id = fields.Many2one('res.users')

View File

@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details
from odoo import api, models
from odoo.http import request
class Http(models.AbstractModel):
_inherit = 'ir.http'
def session_info(self):
# Show company change option even if single company available
is_bg_color = self.env.user.table_color
res = super(Http, self).session_info()
# user = request.env.user
company = self.env.company
session_sid = request.session.sid
if self.env.user.image_1920:
image = self.env.user.image_1920.decode('utf-8')
else:
image = ''
res.update({'bg_color':is_bg_color,'user_image':image,'session_sid':session_sid,'spiffy_installed':True})
if self.env.user.has_group('base.group_user'):
res.update({
"display_switch_company_menu": True,
"prevent_auto_save_warning_msg": company.prevent_auto_save_warning if company.prevent_auto_save_warning else '',
})
return res

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details
from odoo import models, fields, api
class IrUiMenu(models.Model):
_inherit = "ir.ui.menu"
icon_img = fields.Image("Menu New Image")
use_icon = fields.Boolean("Use Icon")
icon_class_name = fields.Char("Icon Class Name")

View File

@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details
from odoo import models
from odoo.http import request
class Module(models.Model):
_inherit = "ir.module.module"
def next(self):
"""
Return the action linked to an ir.actions.todo is there exists one that
should be executed. Otherwise, redirect to /web
"""
Todos = self.env['ir.actions.todo']
active_todo = Todos.search([('state', '=', 'open')], limit=1)
if active_todo:
return active_todo.action_launch()
if request.env.user.table_color:
return {
'type': 'ir.actions.act_url',
'target': 'self',
'url': '/web?bg_color=True&tool_color_id=1',
}
else:
return {
'type': 'ir.actions.act_url',
'target': 'self',
'url': '/web',
}

View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Part of Odoo Module Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api
class MultiTab(models.Model):
_name = 'biz.multi.tab'
_description = "Multi Tab"
name = fields.Char("App Name")
url = fields.Char("URL")
actionId = fields.Char("Action ID")
menuId = fields.Char("Menu ID")
user_id = fields.Many2one('res.users')
menu_xmlid = fields.Char("XML ID Name")

View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
from odoo import api, fields, models, _
class PWAshortcuts(models.Model):
_name = 'pwa.shortcuts'
_description = "PWA Shortcuts"
name = fields.Char("Name", required=True)
short_name = fields.Char("Short Name", required=True)
url = fields.Char("URL", required=True, default='/')
description = fields.Char("Description", required=True)
image_192_shortcut = fields.Binary('Image 192px', readonly=False)

View File

@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
import base64
from odoo import api, http, fields, models, tools
from odoo.http import request
from odoo.modules.module import get_resource_path
from odoo.tools.translate import _
class Company(models.Model):
_inherit = 'res.company'
tab_name = fields.Char(string="Backend Tab Name", default="Spiffy", readonly=False)
backend_theme_level = fields.Selection([
('user_level', 'User Level'),
('global_level', 'Global Level')],
default="user_level", required=True, string="Backend Theme Level", readonly=False)
login_page_style = fields.Selection([
('login_style_1', 'Login Style 1'),
('login_style_2', 'Login Style 2'),
('login_style_3', 'Login Style 3'),
('login_style_4', 'Login Style 4')],
default="login_style_1", required=True, string="Login Styles", readonly=False)
login_page_background_img = fields.Binary('Login Background Image', readonly=False, store=True)
login_page_background_color = fields.Char('Login Background Color', default="#f2f6ff", readonly=False)
login_page_text_color = fields.Char('Login Text Color', default="#777777", readonly=False)
show_bg_image = fields.Boolean(string='Add Login Background Image', readonly=False)
def get_login_page_data(self):
admin_users = request.env['res.users'].sudo().search([
('groups_id','in',request.env.ref('base.user_admin').id),
('backend_theme_config','!=',False),
], order="id asc", limit=1)
admin_config = False
if admin_users:
admin_config = admin_users.backend_theme_config
if admin_config:
config_vals = admin_config
else:
config_vals = request.env['backend.config'].sudo().search([], order="id asc", limit=1)
values = {
'config_vals': config_vals,
}
return values
backend_menubar_logo = fields.Binary(
string="Menubar Logo", readonly=False)
backend_menubar_logo_icon = fields.Binary(
string="Menubar Logo Icon", readonly=False)
enable_pwa = fields.Boolean(string='Enable PWA', readonly=False)
app_name_pwa = fields.Char('App Name', readonly=False, default='Spiffy')
short_name_pwa = fields.Char('Short Name', readonly=False, default='Spiffy')
description_pwa = fields.Char('App Description', readonly=False, default='Spiffy')
image_192_pwa = fields.Binary('Image 192px', readonly=False, store=True)
image_512_pwa = fields.Binary('Image 512px', readonly=False, store=True)
start_url_pwa = fields.Char('App Start Url', readonly=False, default='/web')
background_color_pwa = fields.Char('Background Color', readonly=False, default='#0097a7')
theme_color_pwa = fields.Char('Theme Color', readonly=False, default='#0097a7')
pwa_shortcuts_ids = fields.Many2many('pwa.shortcuts', string='PWA Shortcuts')
spiffy_toobar_color = fields.Char('Toolbar Color', readonly=False, default='#0097a7')
prevent_auto_save = fields.Boolean(string='Prevent Auto Save', readonly=False)
prevent_auto_save_warning = fields.Char('Auto Save Warning', translate=True, default="Autosave is disabled, Click on save button.", readonly=False)

View File

@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
# Developed by Bizople Solutions Pvt. Ltd.
from odoo.modules.module import get_resource_path
from odoo import api, http, fields, models, tools, _
from odoo.http import request
import base64
class ResConfig(models.TransientModel):
_inherit = 'res.config.settings'
spiffy_favicon = fields.Binary(related='company_id.favicon',
string="Backend Tab Favicon", readonly=False)
tab_name = fields.Char(related='company_id.tab_name',
string="Backend Tab Name", readonly=False)
backend_theme_level = fields.Selection(
related='company_id.backend_theme_level', string="Backend Theme Level", required=True, readonly=False)
login_page_style = fields.Selection(
related='company_id.login_page_style', string="Login Styles", required=True, readonly=False)
login_page_background_img = fields.Binary(
related='company_id.login_page_background_img', string="Login Background Image", readonly=False)
login_page_background_color = fields.Char(
related='company_id.login_page_background_color', string='Login Background Color', readonly=False)
login_page_text_color = fields.Char(
related='company_id.login_page_text_color', string='Login Text Color', readonly=False)
show_bg_image = fields.Boolean(
related='company_id.show_bg_image', string='Add Login Background Image', readonly=False)
backend_menubar_logo = fields.Binary(
related='company_id.backend_menubar_logo', string="Menubar Logo", readonly=False)
backend_menubar_logo_icon = fields.Binary(
related='company_id.backend_menubar_logo_icon', string="Menubar Logo Icon", readonly=False)
# Fields for PWA start
enable_pwa = fields.Boolean(
string='Enable PWA', related='company_id.enable_pwa', readonly=False,)
app_name_pwa = fields.Char(
'App Name', related='company_id.app_name_pwa', readonly=False)
short_name_pwa = fields.Char(
'Short Name', related='company_id.short_name_pwa', readonly=False)
description_pwa = fields.Char(
'App Description', related='company_id.description_pwa', readonly=False)
image_192_pwa = fields.Binary(
'Image 192px', related='company_id.image_192_pwa', readonly=False)
image_512_pwa = fields.Binary(
'Image 512px', related='company_id.image_512_pwa', readonly=False)
start_url_pwa = fields.Char(
'App Start Url', related='company_id.start_url_pwa', readonly=False)
background_color_pwa = fields.Char(
'Background Color', related='company_id.background_color_pwa', readonly=False)
theme_color_pwa = fields.Char(
'Theme Color', related='company_id.theme_color_pwa', readonly=False)
pwa_shortcuts_ids = fields.Many2many(
related='company_id.pwa_shortcuts_ids', readonly=False)
# Fields for PWA end
spiffy_toobar_color = fields.Char('Toolbar Color', related='company_id.spiffy_toobar_color', readonly=False)
prevent_auto_save = fields.Boolean(
related='company_id.prevent_auto_save', string='Prevent Auto Save ?', readonly=False)
prevent_auto_save_warning = fields.Char('Auto Save Warning', related='company_id.prevent_auto_save_warning', readonly=False)

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Part of Odoo Module Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api
class User(models.Model):
_inherit = "res.users"
app_ids = fields.One2many('favorite.apps', 'user_id',string="Favorite Apps")
bookmark_ids = fields.One2many('bookmark.link', 'user_id',string="Bookmark Links")
dark_mode = fields.Boolean(string="Is dark Mode Active", default=False)
vertical_sidebar_pinned = fields.Boolean(string="Pinned Sidebar", default=True)
backend_theme_config = fields.Many2one('backend.config', string="Backend Config", copy=False)
multi_tab_ids = fields.One2many('biz.multi.tab', 'user_id', string="Multi Tabs")
enable_todo_list = fields.Boolean(string="Enable To Do List", default=True)
todo_list_ids = fields.One2many('todo.list', 'user_id', string="To Do List")
table_color = fields.Boolean(string="Is Body Color")
tool_color_id = fields.Char(string="Tool Color")
@property
def SELF_READABLE_FIELDS(self):
return super().SELF_READABLE_FIELDS + ['enable_todo_list']
@property
def SELF_WRITEABLE_FIELDS(self):
return super().SELF_WRITEABLE_FIELDS + ['enable_todo_list']

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Part of Odoo Module Developed by Bizople Solutions Pvt. Ltd.
# See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api
class ToDoList(models.Model):
_name = "todo.list"
_description = "To Do List"
_order = 'write_date desc, create_date desc'
def _default_sequence(self):
return (self.search([], order="sequence desc", limit=1).sequence or 0) + 1
sequence = fields.Integer('sequence', default=_default_sequence)
name = fields.Char("Title")
description = fields.Html('Description')
# marked_done = fields.Boolean("Done?")
user_id = fields.Many2one('res.users', string="User")
create_date = fields.Datetime(string="Created on")
write_date = fields.Datetime("Last Updated On", index=True)
note_color_pallet = fields.Selection([
('pallet_1', 'Pallet 1'),
('pallet_2', 'Pallet 2'),
('pallet_3', 'Pallet 3'),
('pallet_4', 'Pallet 4'),
('pallet_5', 'Pallet 5'),
('pallet_6', 'Pallet 6'),
('pallet_7', 'Pallet 7'),
],default="pallet_1", string="Notes Color Pallets", required=True)

View File

@@ -0,0 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_favorite_apps,access_favorite_apps,model_favorite_apps,base.group_user,1,0,0,0
access_bookmark_link,access_bookmark_link,model_bookmark_link,base.group_user,1,0,0,0
access_backend_config,access_backend_config,model_backend_config,base.group_user,1,1,1,0
access_pwa_shortcuts,access_pwa_shortcuts,model_pwa_shortcuts,,1,1,1,1
access_biz_multi_tab,access_biz_multi_tab,model_biz_multi_tab,base.group_user,1,0,0,0
access_todo_list,access_todo_list,model_todo_list,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_favorite_apps access_favorite_apps model_favorite_apps base.group_user 1 0 0 0
3 access_bookmark_link access_bookmark_link model_bookmark_link base.group_user 1 0 0 0
4 access_backend_config access_backend_config model_backend_config base.group_user 1 1 1 0
5 access_pwa_shortcuts access_pwa_shortcuts model_pwa_shortcuts 1 1 1 1
6 access_biz_multi_tab access_biz_multi_tab model_biz_multi_tab base.group_user 1 0 0 0
7 access_todo_list access_todo_list model_todo_list 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

View File

@@ -0,0 +1,654 @@
<section class="" style=" border-radius: 16px;">
<section class="mb-4 bizople_partner_logo" style="padding:35px; background-color: #1b1b1b; border-radius: 16px;">
<div class="row justify-content-md-between justify-content-center align-items-center py-2 mx-0">
<div class="col-md-3">
<a href="https://www.bizople.com/" style="text-decoration:none;">
<img class="img img-fluid" style="text-align: center;" src="bizople-white-logo.png"></img>
</a>
</div>
<div class="s_btn text-center pt0 col-md-6" data-name="Button">
<a href="#" class="mx-1 btn btn-primary btn-lg" style="background-color: #0097a7; border: 1px solid #0097a7; color:white; font-family: Montserrat;"> <i class="fa fa-check-square-o"></i> Community</a>
<a href="mailto:info@bizople.com" class="mx-1 btn btn-primary btn-lg" style="background-color: #0097a7; border: 1px solid #0097a7; color:white; font-family: Montserrat;">Email Us</a>
<!-- <a href="skype:live:bizoples?chat" class="mx-1 btn btn-primary btn-lg" style="background-color: #0097a7; border: 1px solid #0097a7; color:white; font-family: Montserrat;">Skype</a> -->
</div>
<div class="col-md-3">
<img class="img img-fluid" style="height: 80px; text-align: center;" src="odoo_ready_partner_logo.png"></img>
</div>
</div>
</section>
<div class="index-main-banner text-center" >
<div class="gif-image">
<img class="img img-fluid" style="text-align:center; border-radius: 16px;" src="Index-main-banner.jpg"/>
</div>
<img class="img img-fluid shadow-sm my-4" style="text-align:center; border-radius: 16px;" src="spiffy-mobile-app-banner.jpg"/>
<div class="main-feature-banner p-3 p-md-5 text-center">
<h2 class="mb-5 w-lg-75 mx-auto" style="font-size: calc(min(40px, 5vw)); color: #0081a5;">Enhance your Productivity with the Advance Key Features</h2>
<img class="img img-fluid" style="text-align:center" src="feature-banner-no-split-view.png"/>
</div>
</div>
</section>
<section class="my-4 index-enterprise">
<div class="spiffy-enterprise-banner text-center">
<a href="https://apps.odoo.com/apps/themes/16.0/spiffy_theme_backend_ent/">
<img class="img img-fluid" style="text-align:center; border-radius: 16px;" src="spiffy-enterprise.png" />
</a>
</div>
</section>
<section class="index-tabs mt-4" style=" border-radius: 16px;">
<ul class="nav nav-tabs justify-content-center bg-white mb-5 d-none" id="myTab" role="tablist" style="border-bottom:1px solid #CFCFCF;">
<li class="nav-item">
<a class="nav-link active" id="spiffy-main-features" data-bs-toggle="tab" href="#main-features" role="tab" style="color:#1b1b1b;">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" id="spiffy-faq" data-bs-toggle="tab" href="#faq" role="tab" style="color:#1b1b1b;">FAQs</a>
</li>
<li class="nav-item">
<a class="nav-link" id="spiffy-release-note" data-bs-toggle="tab" href="#release-note" role="tab" style="color:#1b1b1b;">Release Notes</a>
</li>
<li class="nav-item">
<a class="nav-link" id="spiffy-contact" data-bs-toggle="tab" href="#contact" role="tab" style="color:#1b1b1b;">Contact Us</a>
</li>
</ul>
<div class="tab-content" id="spiffy-index-tabs">
<div class="tab-pane fade show active" id="main-features" role="tabpanel">
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="theme-style.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="theme-color.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="index-responsive.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="spiffy-index-pwa.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="rtl-support.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="multi-tab.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="3d-icon-pack.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="notes.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="list-density.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="list-sticky-header-footer.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="modal-drag-resize.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="prevent-auto-save.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="chatter-attachment-in-list.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="app-drawer.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="drawer-global-search.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="top-menu-position.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="darklight-pin-unpin.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="branding.gif"/>
<!-- <img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="split-view.gif"/> -->
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="zoom-fullscreen.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="bookmark.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="fav-apps.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="app-icon-config.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="refresh-btn.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="separator-tab-popup-styles.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="loaders-fontfamily.gif"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="fontsize-radio-checkbox.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="loginpage.gif"/>
<section class="index-alert mt-5">
<div class="s_alert w-100 alert-delta d-md-flex align-items-center justify-content-center p-3 shadow-sm" style="border-radius: 16px; color: #2f4752; background-color: #dee7ec; border-color: #d1dee4;">
<i class="fa fa-2x fa-info border rounded-circle text-center" style="border-color: #121212 !important; min-width: 50px; width: 50px; height: 50px; line-height: 50px;"></i>
<div class="s_alert_content ml-3 pt-3 pt-md-0">
<p class="" style="font-size: calc(min(18px, 4vw));">
<b>Note:</b> <br/> If you are using Website App and want to have web like login page design, you can purchase the <a href="https://apps.odoo.com/apps/modules/16.0/spiffy_website_login/" class="">Website Login Add-on module</a> from the store
</p>
</div>
</div>
</section>
<section class="index-spiffy-modules-link my-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="spiffy-ce-module">
<div class="index-spiffy-modules-title text-center mb-3">
<a class="" href="https://apps.odoo.com/apps/modules/16.0/spiffy_website_login/">
<h2 class="mb-0 mx-auto" style="font-size: 23px; color: #0097a7;">Spiffy Backend Theme - Website Login Addon</h2>
</a>
</div>
<a class="" href="https://apps.odoo.com/apps/modules/16.0/spiffy_website_login/">
<img class="img img-fluid" src="spiffy_website_login_addon.png"/>
</a>
</div>
</div>
</div>
</div>
</section>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="lang-company-debug.jpg"/>
<img class="img img-fluid shadow-sm mb-4" style="text-align:center; border-radius: 16px;" src="user-level.jpg"/>
</div>
</div>
</section>
<section class="index-all-features" style=" border-radius: 16px;">
<div class="all-feature-title text-center">
<h2 class="mb-5 w-lg-75 mx-auto" style="font-size: calc(min(40px, 5vw)); color: #0097a7;">All Features</h2>
</div>
<div class="container">
<div class="row">
<!-- DUMMY COL FOR FEATURE PILL -->
<!-- <div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<img class="img img-fluid" style="width: 40px; height: 40px; object-fit: contain;" src="feature-brush-line.png" />
<span class="" style="font-size: 24px; color: #0097A7;"">1.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">3 in 1 Theme Styles</span>
</span>
</div>
</div> -->
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">1.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">3 in 1 Theme Styles</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">2.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Chatter Box Position</span>
</span>
</div>
</div>
<!-- <div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;"">3.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Tree-Form Split View</span>
</span>
</div>
</div> -->
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">3.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Attachment in List View</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">4.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Vertical/Horizontal Menu Style</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">5.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">4 Seprator Styles</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;"">6.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">4 Tab Style</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;"">7.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">4 Checkbox Style</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;"">8.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">4 Radio Style</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;"">9.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">4 Popup Animations</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">10.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">9 Theme Color Pallets</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">11.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Custom Theme Color option</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">12.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">9 App Drawer Color Pallet</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">13.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Custom App Drawer Color</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">14.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">13 Unique Font Styles</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">15.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Font Sizes</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">16.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">10 Loading Icons</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">17.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">4 Login Page Designs</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">18.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Configurable App Icons</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">19.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Global Search</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">20.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Full Screen</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">21.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Zoom In / Zoom Out</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">22.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Bookmarks</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">23.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Dark/Light Mode</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">24.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Language Selector</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">25.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Company Selector</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">26.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Lock/Unlock Sidebar</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">27.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Debug Activator</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">28.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">RTL Supported</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">29.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">User Access (User/Global)</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">30.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Greetings on Menubar</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">31.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Custom Branding</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">32.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">PWA with Shortcuts</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">33.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Favorite App Island</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">34.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Refresh Button</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">35.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Multiple Tab</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">36.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Notes</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">37.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">List/Tree View Density</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">38.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">List/Tree View Sticky Header &amp; Footer</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">39.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Prevent Auto Save</span>
</span>
</div>
</div>
<div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">40.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Modal Draggable &amp; Resizable</span>
</span>
</div>
</div>
<!-- <div class="col-md-6 col-lg-4 col-xl-3 px-2 my-2">
<div class="align-content-center d-flex p-3 rounded-pill shadow-sm" style="font-size: 16px; background-color: #0097A7; color: #fff;">
<span style="min-width: 50px; height: 50px; line-height: 50px;" class="bg-white rounded-circle shadow-sm text-center">
<span class="" style="font-size: 24px; color: #0097A7;">36.</span>
</span>
<span class="align-content-center d-flex flex-column flex-fill px-3 my-auto">
<span class="">Tree-Form Split View</span>
</span>
</div>
</div> -->
</div>
</div>
</section>
<section class="index-services-support mt-5" style=" border-radius: 16px;">
<p class="mb-4" style="font-size: 17px; text-align: center;">
<b>Note:</b> This Product is developed and tested with Odoo Addons
</p>
<section class="align-items-center g-0 justify-content-center mb-4 row py-5 px-3 px-md-5"
style="background-color: #0e0e0e; color: #fff; border-radius: 16px;">
<div class="col-md-7">
<div>
<b style="font-size: 22px;">Spiffy Mobile App Note:</b>
<br/>
<ul class="pt-2" style="font-size: 16px;">
<li>Spiffy Mobile App is an Android and iOS application works with the Spiffy Backend Theme.</li>
<li>It is a complementary / FREE application with the Spiffy Backend Theme and it has no relation with the theme working.</li>
<li>The Application works well but is not satisfying the customer's specific needs it would not be considered to claim a refund for the Spiffy Backend Theme.</li>
<li>
Push Notification and 2-Factor Authentication functionalities are in process and will be available in the future version of Spiffy mobile Application.
</li>
</ul>
</div>
</div>
<div class="col-md-5 text-center">
<img class="img img-fluid" width="300" height="300" src="spiffy-mobile-app-icon.png"/>
</div>
</section>
<img class="img img-fluid mb-4" src="support_banner.jpg" style="border-radius:6px;"/>
<img class="img img-fluid" src="service-banner.jpg" style="border-radius:6px;"/>
</section>
<section class="features-changelog-main mt-5 p-5" style="background-color: white; border-radius: 16px; box-shadow: 0 0px 10px rgba(0, 0, 0, 0.075) !important;">
<section id="changelog">
<div class="log-title">
<p style="font-size: 30px;">Release Notes</p>
</div>
<div class="log-details">
<h3 class="mb-3 d-flex align-items-center w-100" style="font-size: 24px;color: #1b1b1b;font-weight: 600;"><span class="text-info">v2.0</span></h3>
<p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;"><span class="mr-2 d-inline-block badge badge-success" style="color: #ffffff;font-size: 14px; vertical-align: middle;">New</span>Compatibility with Spiffy: Odoo Mobile Application (android/ios)</p>
<h3 class="mb-3 d-flex align-items-center w-100" style="font-size: 24px;color: #1b1b1b;font-weight: 600;"><span class="text-info">v16.0.0.4</span></h3>
<p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;"><span class="mr-2 d-inline-block badge badge-success" style="color: #ffffff;font-size: 14px; vertical-align: middle;">New</span>New Features: Notes, List/Tree View Density, List/Tree View Sticky Header &amp; Footer, Prevent Auto Save, Modal Draggable &amp; Resizable.</p>
<h3 class="mb-3 d-flex align-items-center w-100" style="font-size: 24px;color: #1b1b1b;font-weight: 600;"><span class="text-info">v16.0.0.3</span></h3>
<p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;"><span class="mr-2 d-inline-block badge badge-warning" style="color: #ffffff;font-size: 14px; vertical-align: middle;">Fixed</span>Improvements on Login Styles and Design.</p>
<h3 class="mb-3 d-flex align-items-center w-100" style="font-size: 24px;color: #1b1b1b;font-weight: 600;"><span class="text-info">v16.0.0.2</span></h3>
<p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;"><span class="mr-2 d-inline-block badge badge-warning" style="color: #ffffff;font-size: 14px; vertical-align: middle;">Fixed</span>Minor bug fixes and improvements.</p>
<h3 class="mb-3 d-flex align-items-center w-100" style="font-size: 24px;color: #1b1b1b;font-weight: 600;"><span class="text-info">v16.0.0.1</span></h3>
<p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;"><span class="mr-2 d-inline-block badge badge-success" style="color: #ffffff;font-size: 14px; vertical-align: middle;">New</span>Multiple Tab</p>
<p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;"><span class="mr-2 d-inline-block badge badge-warning" style="color: #ffffff;font-size: 14px; vertical-align: middle;">Fixed</span>Minor bug fixes and improvements.</p>
<h3 class="mb-3 d-flex align-items-center w-100" style="font-size: 24px;color: #1b1b1b;font-weight: 600;"><span class="text-info">v16.0.0.0</span></h3>
<p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;">Initial Release</p>
<!-- badge badge-warning FOR FIXES -->
<!-- badge badge-success FOR NEW -->
<!-- badge badge-info FOR UPDATES -->
<!-- for update tag use this -->
<!-- <p class="d-flex align-items-center w-100" style="color: #1b1b1b;font-size: 18px;"><span class="mr-2 d-inline-block o_gradient" style="color: #ffffff;font-size: 14px; vertical-align: middle;">Update</span>Initial Release</p> -->
</div>
</section>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

View File

@@ -0,0 +1 @@
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 10'><defs><style>.cls-1{opacity:0.3;}</style></defs><path class='cls-1' d='M2.68.82h0a.27.27,0,0,0-.36,0h0L.82,2.32a.27.27,0,0,0,0,.36.27.27,0,0,0,.36,0L2.25,1.6V9a.25.25,0,0,0,.5,0V1.6L3.82,2.68a.27.27,0,0,0,.36,0,.27.27,0,0,0,0-.36Z'/><path class='cls-1' d='M8.18,7.32a.27.27,0,0,0-.36,0L6.75,8.4V1a.25.25,0,0,0-.5,0V8.4L5.18,7.32a.25.25,0,0,0-.36.36l1.5,1.5a.27.27,0,0,0,.36,0l1.5-1.5A.27.27,0,0,0,8.18,7.32Z'/></svg>

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto; animation-play-state: running; animation-delay: 0s;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="84" cy="50" r="10" fill="#399ddb" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="0.25s" calcMode="spline" keyTimes="0;1" values="10;0" keySplines="0 0.5 0.5 1" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="fill" repeatCount="indefinite" dur="1s" calcMode="discrete" keyTimes="0;0.25;0.5;0.75;1" values="#399ddb;#005488;#0078c2;#0085d7;#399ddb" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle><circle cx="16" cy="50" r="10" fill="#399ddb" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle><circle cx="50" cy="50" r="10" fill="#0085d7" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.25s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.25s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle><circle cx="84" cy="50" r="10" fill="#0078c2" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.5s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.5s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle><circle cx="16" cy="50" r="10" fill="#005488" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.75s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.75s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle>
<!-- [ldio] generated by https://loading.io/ --></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

Some files were not shown because too many files have changed in this diff Show More