Merge branch 'develop' into feat-desk-refresh
This commit is contained in:
commit
37f03069bf
32 changed files with 182 additions and 81 deletions
|
|
@ -413,13 +413,7 @@ def sync_database(rollback: bool) -> bool:
|
|||
|
||||
|
||||
def serve(
|
||||
host=None,
|
||||
port=8000,
|
||||
profile=False,
|
||||
no_reload=False,
|
||||
no_threading=False,
|
||||
site=None,
|
||||
sites_path=".",
|
||||
port=8000, profile=False, no_reload=False, no_threading=False, site=None, sites_path="."
|
||||
):
|
||||
global application, _site, _sites_path
|
||||
_site = site
|
||||
|
|
@ -444,7 +438,7 @@ def serve(
|
|||
log.setLevel(logging.ERROR)
|
||||
|
||||
run_simple(
|
||||
host,
|
||||
"0.0.0.0",
|
||||
int(port),
|
||||
application,
|
||||
exclude_patterns=["test_*"],
|
||||
|
|
|
|||
|
|
@ -481,43 +481,35 @@ def install_app(context, apps, force=False):
|
|||
@click.option("--format", "-f", type=click.Choice(["text", "json"]), default="text")
|
||||
@pass_context
|
||||
def list_apps(context, format):
|
||||
"List apps in site"
|
||||
"""
|
||||
List apps in site.
|
||||
"""
|
||||
|
||||
summary_dict = {}
|
||||
|
||||
def fix_whitespaces(text):
|
||||
if site == context.sites[-1]:
|
||||
text = text.rstrip()
|
||||
if len(context.sites) == 1:
|
||||
text = text.lstrip()
|
||||
return text
|
||||
def format_app(app):
|
||||
name_len = max(len(app.app_name) for app in apps)
|
||||
ver_len = max(len(app.app_version) for app in apps)
|
||||
template = f"{{0:{name_len}}} {{1:{ver_len}}} {{2}}"
|
||||
return template.format(app.app_name, app.app_version, app.git_branch)
|
||||
|
||||
for site in context.sites:
|
||||
frappe.init(site=site)
|
||||
frappe.connect()
|
||||
site_title = click.style(f"{site}", fg="green") if len(context.sites) > 1 else ""
|
||||
installed_apps_info = []
|
||||
|
||||
apps = frappe.get_single("Installed Applications").installed_applications
|
||||
|
||||
if apps:
|
||||
name_len, ver_len = (max(len(x.get(y)) for x in apps) for y in ["app_name", "app_version"])
|
||||
template = f"{{0:{name_len}}} {{1:{ver_len}}} {{2}}"
|
||||
|
||||
installed_applications = [
|
||||
template.format(app.app_name, app.app_version, app.git_branch) for app in apps
|
||||
]
|
||||
applications_summary = "\n".join(installed_applications)
|
||||
summary = f"{site_title}\n{applications_summary}\n"
|
||||
summary_dict[site] = [app.app_name for app in apps]
|
||||
|
||||
installed_apps_info.extend(format_app(app) for app in apps)
|
||||
else:
|
||||
installed_applications = frappe.get_installed_apps()
|
||||
applications_summary = "\n".join(installed_applications)
|
||||
summary = f"{site_title}\n{applications_summary}\n"
|
||||
summary_dict[site] = installed_applications
|
||||
installed_apps_info.extend(frappe.get_installed_apps())
|
||||
|
||||
summary = fix_whitespaces(summary)
|
||||
installed_apps_info_str = "\n".join(installed_apps_info)
|
||||
summary = f"{site_title}\n{installed_apps_info_str}\n"
|
||||
summary_dict[site] = [app.app_name for app in apps]
|
||||
|
||||
if format == "text" and applications_summary and summary:
|
||||
if format == "text" and installed_apps_info and summary:
|
||||
print(summary)
|
||||
|
||||
frappe.destroy()
|
||||
|
|
|
|||
|
|
@ -922,7 +922,6 @@ def run_ui_tests(
|
|||
|
||||
|
||||
@click.command("serve")
|
||||
@click.option("--host", default="127.0.0.1")
|
||||
@click.option("--port", default=8000)
|
||||
@click.option("--profile", is_flag=True, default=False)
|
||||
@click.option("--noreload", "no_reload", is_flag=True, default=False)
|
||||
|
|
@ -931,7 +930,6 @@ def run_ui_tests(
|
|||
@pass_context
|
||||
def serve(
|
||||
context,
|
||||
host="127.0.0.1",
|
||||
port=None,
|
||||
profile=False,
|
||||
no_reload=False,
|
||||
|
|
@ -953,7 +951,6 @@ def serve(
|
|||
no_threading = True
|
||||
no_reload = True
|
||||
frappe.app.serve(
|
||||
host=host,
|
||||
port=port,
|
||||
profile=profile,
|
||||
no_reload=no_reload,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
frappe.ui.form.on("User", {
|
||||
before_load: function (frm) {
|
||||
var update_tz_select = function (user_language) {
|
||||
frm.set_df_property("time_zone", "options", [""].concat(frappe.all_timezones));
|
||||
let update_tz_options = function () {
|
||||
frm.fields_dict.time_zone.set_data(frappe.all_timezones);
|
||||
};
|
||||
|
||||
if (!frappe.all_timezones) {
|
||||
|
|
@ -9,11 +9,11 @@ frappe.ui.form.on("User", {
|
|||
method: "frappe.core.doctype.user.user.get_timezones",
|
||||
callback: function (r) {
|
||||
frappe.all_timezones = r.message.timezones;
|
||||
update_tz_select();
|
||||
update_tz_options();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
update_tz_select();
|
||||
update_tz_options();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@
|
|||
},
|
||||
{
|
||||
"fieldname": "time_zone",
|
||||
"fieldtype": "Select",
|
||||
"fieldtype": "Autocomplete",
|
||||
"label": "Time Zone"
|
||||
},
|
||||
{
|
||||
|
|
@ -762,7 +762,7 @@
|
|||
"link_fieldname": "user"
|
||||
}
|
||||
],
|
||||
"modified": "2023-06-05 17:26:04.127555",
|
||||
"modified": "2023-09-18 22:19:49.933972",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "User",
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class User(Document):
|
|||
simultaneous_sessions: DF.Int
|
||||
social_logins: DF.Table[UserSocialLogin]
|
||||
thread_notify: DF.Check
|
||||
time_zone: DF.Literal
|
||||
time_zone: DF.Autocomplete | None
|
||||
unsubscribed: DF.Check
|
||||
user_emails: DF.Table[UserEmail]
|
||||
user_image: DF.AttachImage | None
|
||||
|
|
|
|||
|
|
@ -879,7 +879,9 @@ class Database:
|
|||
"""
|
||||
from frappe.model.utils import is_single_doctype
|
||||
|
||||
if (dn is None or dt == dn) and is_single_doctype(dt):
|
||||
if dn is None or dt == dn:
|
||||
if not is_single_doctype(dt):
|
||||
return
|
||||
deprecation_warning(
|
||||
"Calling db.set_value on single doctype is deprecated. This behaviour will be removed in future. Use db.set_single_value instead."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"script",
|
||||
"type"
|
||||
"type",
|
||||
"committed"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -23,11 +24,18 @@
|
|||
"hidden": 1,
|
||||
"label": "Type",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "committed",
|
||||
"fieldtype": "Check",
|
||||
"label": "Committed",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2023-07-27 22:52:37.239039",
|
||||
"modified": "2023-09-19 13:02:56.332137",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Desk",
|
||||
"name": "Console Log",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class ConsoleLog(Document):
|
|||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
committed: DF.Check
|
||||
script: DF.Code | None
|
||||
type: DF.Data | None
|
||||
# end: auto-generated types
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@
|
|||
"options": "DocType"
|
||||
},
|
||||
{
|
||||
"description": "If set, only user with these roles can access this chart. If not set, DocType or Report permissions will be used.",
|
||||
"fieldname": "roles",
|
||||
"fieldtype": "Table",
|
||||
"label": "Roles",
|
||||
|
|
@ -287,7 +288,7 @@
|
|||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2023-08-28 20:20:54.186299",
|
||||
"modified": "2023-09-18 13:41:05.263676",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Desk",
|
||||
"name": "Dashboard Chart",
|
||||
|
|
|
|||
|
|
@ -79,7 +79,11 @@ def has_permission(doc, ptype, user):
|
|||
if "System Manager" in roles:
|
||||
return True
|
||||
|
||||
if doc.chart_type == "Report":
|
||||
if doc.roles:
|
||||
allowed = [d.role for d in doc.roles]
|
||||
if has_common(roles, allowed):
|
||||
return True
|
||||
elif doc.chart_type == "Report":
|
||||
if doc.report_name in get_allowed_report_names():
|
||||
return True
|
||||
else:
|
||||
|
|
@ -87,11 +91,6 @@ def has_permission(doc, ptype, user):
|
|||
if doc.document_type in allowed_doctypes:
|
||||
return True
|
||||
|
||||
if doc.roles:
|
||||
allowed = [d.role for d in doc.roles]
|
||||
if has_common(roles, allowed):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -108,8 +108,8 @@ let add_custom_button = (frm) => {
|
|||
tour_name: frm.doc.name,
|
||||
},
|
||||
});
|
||||
},
|
||||
delete frappe.boot.user.onboarding_status[frm.doc.name]
|
||||
delete frappe.boot.user.onboarding_status[frm.doc.name];
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ class SystemConsole(Document):
|
|||
frappe.db.commit()
|
||||
else:
|
||||
frappe.db.rollback()
|
||||
frappe.get_doc(dict(doctype="Console Log", script=self.console, type=self.type)).insert()
|
||||
frappe.get_doc(
|
||||
dict(doctype="Console Log", script=self.console, type=self.type, committed=self.commit)
|
||||
).insert()
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ def get_internal_links(doc, link, link_doctype):
|
|||
elif isinstance(link, list):
|
||||
# get internal links in child documents
|
||||
table_fieldname, link_fieldname = link
|
||||
for row in doc.get(table_fieldname):
|
||||
for row in doc.get(table_fieldname) or []:
|
||||
value = row.get(link_fieldname)
|
||||
if value and value not in names:
|
||||
names.append(value)
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ def update_global_settings(args):
|
|||
|
||||
update_system_settings(args)
|
||||
update_user_name(args)
|
||||
set_timezone(args)
|
||||
|
||||
|
||||
def run_post_setup_complete(args):
|
||||
|
|
@ -248,6 +249,12 @@ def update_user_name(args):
|
|||
add_all_roles_to(args.get("name"))
|
||||
|
||||
|
||||
def set_timezone(args):
|
||||
if args.get("timezone"):
|
||||
for name in frappe.STANDARD_USERS:
|
||||
frappe.db.set_value("User", name, "time_zone", args.get("timezone"))
|
||||
|
||||
|
||||
def parse_args(args):
|
||||
if not args:
|
||||
args = frappe.local.form_dict
|
||||
|
|
|
|||
|
|
@ -606,6 +606,20 @@ class TestInboundMail(FrappeTestCase):
|
|||
reference_doc = inbound_mail.reference_document()
|
||||
self.assertEqual(todo.name, reference_doc.name)
|
||||
|
||||
def test_reference_document_by_subject_match_with_accents(self):
|
||||
subject = "Nouvelle tâche à faire 😃"
|
||||
todo = self.new_todo(sender="test_sender@example.com", description=subject)
|
||||
|
||||
mail_content = (
|
||||
self.get_test_mail(fname="incoming-subject-placeholder.raw")
|
||||
.replace("{{ subject }}", f"RE: {subject}")
|
||||
.encode("utf-8")
|
||||
) # note: encode to bytes because that's what triggered the error
|
||||
email_account = frappe.get_doc("Email Account", "_Test Email Account 1")
|
||||
inbound_mail = InboundMail(mail_content, email_account, 12345, 1)
|
||||
reference_doc = inbound_mail.reference_document()
|
||||
self.assertEqual(todo.name, reference_doc.name)
|
||||
|
||||
def test_create_communication_from_mail(self):
|
||||
# Create email queue record
|
||||
mail_content = self.get_test_mail(fname="incoming-2.raw")
|
||||
|
|
|
|||
|
|
@ -402,11 +402,19 @@ class Email:
|
|||
"""Parse and decode `Subject` header."""
|
||||
_subject = decode_header(self.mail.get("Subject", "No Subject"))
|
||||
self.subject = _subject[0][0] or ""
|
||||
|
||||
if _subject[0][1]:
|
||||
# Encoding is known by decode_header (might also be unknown-8bit)
|
||||
self.subject = safe_decode(self.subject, _subject[0][1])
|
||||
else:
|
||||
# assume that the encoding is utf-8
|
||||
self.subject = safe_decode(self.subject)[:140]
|
||||
|
||||
if isinstance(self.subject, bytes):
|
||||
# Fall back to utf-8 if the charset is unknown or decoding fails
|
||||
# Replace invalid characters with '<?>'
|
||||
self.subject = self.subject.decode("utf-8", "replace")
|
||||
|
||||
# Convert non-string (e.g. None)
|
||||
# Truncate to 140 chars (can be used as a document name)
|
||||
self.subject = str(self.subject).strip()[:140]
|
||||
|
||||
if not self.subject:
|
||||
self.subject = "No Subject"
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ app_include_css = [
|
|||
"desk.bundle.css",
|
||||
"report.bundle.css",
|
||||
]
|
||||
app_include_icons = ["frappe/public/icons/timeless/icons.svg"]
|
||||
|
||||
doctype_js = {
|
||||
"Web Page": "public/js/frappe/utils/web_template.js",
|
||||
|
|
|
|||
|
|
@ -10,14 +10,16 @@ from frappe import _
|
|||
from frappe.utils import get_request_session
|
||||
|
||||
|
||||
def make_request(method, url, auth=None, headers=None, data=None):
|
||||
def make_request(method, url, auth=None, headers=None, data=None, json=None):
|
||||
auth = auth or ""
|
||||
data = data or {}
|
||||
headers = headers or {}
|
||||
|
||||
try:
|
||||
s = get_request_session()
|
||||
frappe.flags.integration_request = s.request(method, url, data=data, auth=auth, headers=headers)
|
||||
frappe.flags.integration_request = s.request(
|
||||
method, url, data=data, auth=auth, headers=headers, json=json
|
||||
)
|
||||
frappe.flags.integration_request.raise_for_status()
|
||||
|
||||
if frappe.flags.integration_request.headers.get("content-type") == "text/plain; charset=utf-8":
|
||||
|
|
|
|||
5
frappe/public/icons/timeless/test.svg
Normal file
5
frappe/public/icons/timeless/test.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<svg>
|
||||
<symbol id="icon-TEST-ONLY">
|
||||
<rect width="24" height="24" stroke="currentColor" />
|
||||
</symbol>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 109 B |
|
|
@ -10,7 +10,7 @@ frappe.ui.form.ControlIcon = class ControlIcon extends frappe.ui.form.ControlDat
|
|||
|
||||
get_all_icons() {
|
||||
frappe.symbols = [];
|
||||
$("#frappe-symbols > symbol[id]").each(function () {
|
||||
$("#all-symbols > svg > symbol[id]").each(function () {
|
||||
this.id.includes("icon-") && frappe.symbols.push(this.id.replace("icon-", ""));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,11 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
page: this.page,
|
||||
description: __("Redo last action"),
|
||||
});
|
||||
frappe.ui.keys.add_shortcut({
|
||||
shortcut: "ctrl+p",
|
||||
action: () => this.print_doc(),
|
||||
description: __("Print document"),
|
||||
});
|
||||
|
||||
let grid_shortcut_keys = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -235,7 +235,11 @@ export default class BulkOperations {
|
|||
}
|
||||
|
||||
edit(docnames, field_mappings, done) {
|
||||
let field_options = Object.keys(field_mappings).sort();
|
||||
let field_options = Object.keys(field_mappings).sort(function (a, b) {
|
||||
return __(cstr(field_mappings[a].label)).localeCompare(
|
||||
cstr(__(field_mappings[b].label))
|
||||
);
|
||||
});
|
||||
const status_regex = /status/i;
|
||||
|
||||
const default_field = field_options.find((value) => status_regex.test(value));
|
||||
|
|
|
|||
|
|
@ -10,22 +10,12 @@
|
|||
<option value="" disabled selected>{{ __("Select Group By...") }}</option>
|
||||
{% for (var parent_doctype in group_by_conditions) { %}
|
||||
{% for (var val in group_by_conditions[parent_doctype]) { %}
|
||||
{% if (parent_doctype !== doctype) { %}
|
||||
<option
|
||||
data-doctype="{{parent_doctype}}"
|
||||
value="{{group_by_conditions[parent_doctype][val].fieldname}}"
|
||||
>
|
||||
{{ __(group_by_conditions[parent_doctype][val].label) }}
|
||||
({{ __(parent_doctype) }})
|
||||
{{ __(group_by_conditions[parent_doctype][val].label || group_by_conditions[parent_doctype][val].fieldname) }}
|
||||
</option>
|
||||
{% } else { %}
|
||||
<option
|
||||
data-doctype="{{parent_doctype}}"
|
||||
value="{{group_by_conditions[parent_doctype][val].fieldname}}"
|
||||
>
|
||||
{{ __(group_by_conditions[parent_doctype][val].label) }}
|
||||
</option>
|
||||
{% } %}
|
||||
{% } %}
|
||||
{% } %}
|
||||
</select>
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ frappe.ui.GroupBy = class {
|
|||
const tag_field = { fieldname: "_user_tags", fieldtype: "Data", label: __("Tags") };
|
||||
this.group_by_fields[this.doctype] = fields
|
||||
.concat(tag_field)
|
||||
.sort((a, b) => __(a.label).localeCompare(__(b.label)));
|
||||
.sort((a, b) => __(cstr(a.label)).localeCompare(cstr(__(b.label))));
|
||||
this.all_fields[this.doctype] = this.report_view.meta.fields;
|
||||
|
||||
const standard_fields_filter = (df) =>
|
||||
|
|
@ -407,8 +407,9 @@ frappe.ui.GroupBy = class {
|
|||
}
|
||||
|
||||
get_group_by_field_label() {
|
||||
return this.group_by_fields[this.group_by_doctype].find(
|
||||
let field = this.group_by_fields[this.group_by_doctype].find(
|
||||
(field) => field.fieldname == this.group_by_field
|
||||
).label;
|
||||
);
|
||||
return field.label || field.fieldname;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -332,10 +332,39 @@ frappe.utils.sanitise_redirect = (url) => {
|
|||
};
|
||||
})();
|
||||
|
||||
/*
|
||||
* Strips out url containing the text `javascript` with or without any HTML Entities in it
|
||||
**/
|
||||
const sanitise_javascript = (url) => {
|
||||
// please do not ask how or why
|
||||
const REGEX_SCRIPT =
|
||||
/j[\s]*(&#x.{1,7})?a[\s]*(&#x.{1,7})?v[\s]*(&#x.{1,7})?a[\s]*(&#x.{1,7})?s[\s]*(&#x.{1,7})?c[\s]*(&#x.{1,7})?r[\s]*(&#x.{1,7})?i[\s]*(&#x.{1,7})?p[\s]*(&#x.{1,7})?t/gi;
|
||||
/*
|
||||
* Written below split into parts, but actual is in one line regardless of whitespaces
|
||||
* /
|
||||
* j
|
||||
* \s*(&#x.{1,7})?
|
||||
* a
|
||||
* \s*(&#x.{1,7})?
|
||||
* v
|
||||
* \s*(&#x.{1,7})?
|
||||
* a
|
||||
* \s*(&#x.{1,7})?
|
||||
* s
|
||||
* \s*(&#x.{1,7})?
|
||||
* c
|
||||
* \s*(&#x.{1,7})?
|
||||
* r
|
||||
* \s*(&#x.{1,7})?
|
||||
* i
|
||||
* \s*(&#x.{1,7})?
|
||||
* p
|
||||
* \s*(&#x.{1,7})?
|
||||
* t
|
||||
* /gi
|
||||
* */
|
||||
const REGEX_ESC_UNIT = /\s*(&#x.{1,7})?/;
|
||||
const REGEX_SCRIPT = new RegExp(
|
||||
Array.from("javascript").join(REGEX_ESC_UNIT.source),
|
||||
"gi"
|
||||
);
|
||||
|
||||
return url.replace(REGEX_SCRIPT, "");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -693,6 +693,12 @@ class TestDBSetValue(FrappeTestCase):
|
|||
current_value = frappe.db.get_single_value("System Settings", "deny_multiple_sessions")
|
||||
self.assertEqual(current_value, changed_value)
|
||||
|
||||
def test_none_no_set_value(self):
|
||||
frappe.db.set_value("User", None, "middle_name", "test")
|
||||
with self.assertQueryCount(0):
|
||||
frappe.db.set_value("User", None, "middle_name", "test")
|
||||
frappe.db.set_value("User", "User", "middle_name", "test")
|
||||
|
||||
def test_update_single_row_single_column(self):
|
||||
frappe.db.set_value("ToDo", self.todo1.name, "description", "test_set_value change 1")
|
||||
updated_value = frappe.db.get_value("ToDo", self.todo1.name, "description")
|
||||
|
|
|
|||
|
|
@ -391,6 +391,27 @@ class TestWebsite(FrappeTestCase):
|
|||
delattr(frappe.local, "request")
|
||||
frappe.set_user("Guest")
|
||||
|
||||
def test_include_icons(self):
|
||||
from frappe import get_hooks
|
||||
|
||||
TEST_ICONS_PATH = "frappe/public/icons/timeless/test.svg"
|
||||
|
||||
def patched_get_hooks(*args, **kwargs):
|
||||
return_value = get_hooks(*args, **kwargs)
|
||||
if isinstance(return_value, dict) and "app_include_icons" in return_value:
|
||||
return_value.app_include_icons.append(TEST_ICONS_PATH)
|
||||
return return_value
|
||||
|
||||
with patch.object(frappe, "get_hooks", patched_get_hooks):
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
set_request(method="GET", path="/app")
|
||||
content = get_response_content("/app")
|
||||
# icon is available in a symbol tag
|
||||
self.assertIn('id="icon-TEST-ONLY"', content)
|
||||
delattr(frappe.local, "request")
|
||||
frappe.set_user("Guest")
|
||||
|
||||
|
||||
def patched_get_hooks(hook, value):
|
||||
def wrapper(*args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -365,6 +365,11 @@ app_license = "{app_license}"
|
|||
# doctype_tree_js = {{"doctype" : "public/js/doctype_tree.js"}}
|
||||
# doctype_calendar_js = {{"doctype" : "public/js/doctype_calendar.js"}}
|
||||
|
||||
# Svg Icons
|
||||
# ------------------
|
||||
# include app icons in desk
|
||||
# app_include_icons = "{app_name}/public/icons.svg"
|
||||
|
||||
# Home Pages
|
||||
# ----------
|
||||
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ def get_eta(from_time, percent_complete):
|
|||
|
||||
|
||||
def _get_system_timezone():
|
||||
return frappe.db.get_system_setting("time_zone") or "Asia/Kolkata" # Default to India ?!
|
||||
return frappe.get_system_settings("time_zone") or "Asia/Kolkata" # Default to India ?!
|
||||
|
||||
|
||||
def get_system_timezone():
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@
|
|||
<body>
|
||||
{% include "public/icons/timeless/icons.svg" %}
|
||||
{% include "public/icons/espresso/icons.svg" %}
|
||||
<div id="all-symbols" style="display:none!important;">
|
||||
{%- for path in include_icons -%}
|
||||
<!-- {{ path }} -->{%- include path ignore missing -%}
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
{% include "templates/includes/splash_screen.html" %}
|
||||
<div class="main-section">
|
||||
<header></header>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ def get_context(context):
|
|||
|
||||
include_js = hooks.get("app_include_js", []) + frappe.conf.get("app_include_js", [])
|
||||
include_css = hooks.get("app_include_css", []) + frappe.conf.get("app_include_css", [])
|
||||
include_icons = hooks.get("app_include_icons", [])
|
||||
|
||||
context.update(
|
||||
{
|
||||
|
|
@ -51,6 +52,7 @@ def get_context(context):
|
|||
"build_version": frappe.utils.get_build_version(),
|
||||
"include_js": include_js,
|
||||
"include_css": include_css,
|
||||
"include_icons": include_icons,
|
||||
"layout_direction": "rtl" if is_rtl() else "ltr",
|
||||
"lang": frappe.local.lang,
|
||||
"sounds": hooks["sounds"],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue