Merge branch 'rebrand-ui' of https://github.com/frappe/frappe into rebrand-ui
This commit is contained in:
commit
9d01e4cdf3
58 changed files with 936 additions and 639 deletions
|
|
@ -48,6 +48,7 @@ def get_bootinfo():
|
|||
bootinfo.letter_heads = get_letter_heads()
|
||||
bootinfo.active_domains = frappe.get_active_domains()
|
||||
bootinfo.all_domains = [d.get("name") for d in frappe.get_all("Domain")]
|
||||
add_layouts(bootinfo)
|
||||
|
||||
bootinfo.module_app = frappe.local.module_app
|
||||
bootinfo.single_types = [d.name for d in frappe.get_all('DocType', {'issingle': 1})]
|
||||
|
|
@ -309,6 +310,10 @@ def get_additional_filters_from_hooks():
|
|||
|
||||
return filter_config
|
||||
|
||||
def add_layouts(bootinfo):
|
||||
# add routes for readable doctypes
|
||||
bootinfo.doctype_layouts = frappe.get_all('DocType Layout', ['name', 'route', 'document_type'])
|
||||
|
||||
def get_desk_settings():
|
||||
role_list = frappe.get_all('Role', fields=['*'], filters=dict(
|
||||
name=['in', frappe.get_roles()]
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ global_cache_keys = ("app_hooks", "installed_apps",
|
|||
'scheduler_events', 'time_zone', 'webhooks', 'active_domains',
|
||||
'active_modules', 'assignment_rule', 'server_script_map', 'wkhtmltopdf_version',
|
||||
'domain_restricted_doctypes', 'domain_restricted_pages', 'information_schema:counts',
|
||||
'sitemap_routes', 'db_tables', 'doctype_name_map') + doctype_map_keys
|
||||
'sitemap_routes', 'db_tables') + doctype_map_keys
|
||||
|
||||
user_cache_keys = ("bootinfo", "user_recent", "roles", "user_doc", "lang",
|
||||
"defaults", "user_permissions", "home_page", "linked_with",
|
||||
|
|
@ -73,7 +73,7 @@ def clear_doctype_cache(doctype=None):
|
|||
if getattr(frappe.local, 'meta_cache') and (doctype in frappe.local.meta_cache):
|
||||
del frappe.local.meta_cache[doctype]
|
||||
|
||||
for key in ('is_table', 'doctype_modules', 'doctype_name_map', 'document_cache'):
|
||||
for key in ('is_table', 'doctype_modules', 'document_cache'):
|
||||
cache.delete_value(key)
|
||||
|
||||
frappe.local.document_cache = {}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ frappe.ui.form.on('Data Import Legacy', {
|
|||
frm.reload_doc();
|
||||
}
|
||||
if (data.progress) {
|
||||
let progress_bar = $(frm.dashboard.progress_area).find(".progress-bar");
|
||||
let progress_bar = $(frm.dashboard.progress_area.body).find(".progress-bar");
|
||||
if (progress_bar) {
|
||||
$(progress_bar).removeClass("progress-bar-danger").addClass("progress-bar-success progress-bar-striped");
|
||||
$(progress_bar).css("width", data.progress + "%");
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@
|
|||
"label": "Editable Grid"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"default": "0",
|
||||
"depends_on": "eval:!doc.istable && !doc.issingle",
|
||||
"description": "Open a dialog with mandatory fields to create a new record quickly",
|
||||
"fieldname": "quick_entry",
|
||||
|
|
@ -427,7 +427,7 @@
|
|||
"label": "Allow Guest to View"
|
||||
},
|
||||
{
|
||||
"depends_on": "has_web_view",
|
||||
"depends_on": "eval:!doc.istable",
|
||||
"fieldname": "route",
|
||||
"fieldtype": "Data",
|
||||
"label": "Route"
|
||||
|
|
@ -609,7 +609,7 @@
|
|||
"link_fieldname": "reference_doctype"
|
||||
}
|
||||
],
|
||||
"modified": "2020-09-24 13:13:58.227153",
|
||||
"modified": "2020-12-10 15:10:09.227205",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocType",
|
||||
|
|
@ -637,6 +637,7 @@
|
|||
"write": 1
|
||||
}
|
||||
],
|
||||
"route": "doctype",
|
||||
"search_fields": "module",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from frappe.database.schema import validate_column_name, validate_column_length
|
|||
from frappe.model.docfield import supports_translation
|
||||
from frappe.modules.import_file import get_file_path
|
||||
from frappe.model.meta import Meta
|
||||
from frappe.desk.utils import get_doctype_route
|
||||
|
||||
|
||||
class InvalidFieldNameError(frappe.ValidationError): pass
|
||||
|
|
@ -63,15 +64,7 @@ class DocType(Document):
|
|||
|
||||
self.validate_name()
|
||||
|
||||
if self.issingle:
|
||||
self.allow_import = 0
|
||||
self.is_submittable = 0
|
||||
self.istable = 0
|
||||
|
||||
elif self.istable:
|
||||
self.allow_import = 0
|
||||
self.permissions = []
|
||||
|
||||
self.set_defaults_for_single_and_table()
|
||||
self.scrub_field_names()
|
||||
self.set_default_in_list_view()
|
||||
self.set_default_translatable()
|
||||
|
|
@ -79,10 +72,7 @@ class DocType(Document):
|
|||
self.validate_document_type()
|
||||
validate_fields(self)
|
||||
|
||||
if self.istable:
|
||||
# no permission records for child table
|
||||
self.permissions = []
|
||||
else:
|
||||
if not self.istable:
|
||||
validate_permissions(self)
|
||||
|
||||
self.make_amendable()
|
||||
|
|
@ -93,8 +83,6 @@ class DocType(Document):
|
|||
|
||||
if not self.is_new():
|
||||
self.before_update = frappe.get_doc('DocType', self.name)
|
||||
|
||||
if not self.is_new():
|
||||
self.setup_fields_to_fetch()
|
||||
|
||||
check_email_append_to(self)
|
||||
|
|
@ -102,14 +90,20 @@ class DocType(Document):
|
|||
if self.default_print_format and not self.custom:
|
||||
frappe.throw(_('Standard DocType cannot have default print format, use Customize Form'))
|
||||
|
||||
if frappe.conf.get('developer_mode'):
|
||||
self.owner = 'Administrator'
|
||||
self.modified_by = 'Administrator'
|
||||
|
||||
def after_insert(self):
|
||||
# clear user cache so that on the next reload this doctype is included in boot
|
||||
clear_user_cache(frappe.session.user)
|
||||
|
||||
def set_defaults_for_single_and_table(self):
|
||||
if self.issingle:
|
||||
self.allow_import = 0
|
||||
self.is_submittable = 0
|
||||
self.istable = 0
|
||||
|
||||
elif self.istable:
|
||||
self.allow_import = 0
|
||||
self.permissions = []
|
||||
|
||||
def set_default_in_list_view(self):
|
||||
'''Set default in-list-view for first 4 mandatory fields'''
|
||||
if not [d.fieldname for d in self.fields if d.in_list_view]:
|
||||
|
|
@ -134,6 +128,10 @@ class DocType(Document):
|
|||
if not frappe.conf.get("developer_mode") and not self.custom:
|
||||
frappe.throw(_("Not in Developer Mode! Set in site_config.json or make 'Custom' DocType."), CannotCreateStandardDoctypeError)
|
||||
|
||||
if frappe.conf.get('developer_mode'):
|
||||
self.owner = 'Administrator'
|
||||
self.modified_by = 'Administrator'
|
||||
|
||||
def setup_fields_to_fetch(self):
|
||||
'''Setup query to update values for newly set fetch values'''
|
||||
try:
|
||||
|
|
@ -192,6 +190,12 @@ class DocType(Document):
|
|||
|
||||
def validate_website(self):
|
||||
"""Ensure that website generator has field 'route'"""
|
||||
if not self.istable and not self.route:
|
||||
self.route = get_doctype_route(self.name)
|
||||
|
||||
if self.route:
|
||||
self.route = self.route.strip('/')
|
||||
|
||||
if self.has_web_view:
|
||||
# route field must be present
|
||||
if not 'route' in [d.fieldname for d in self.fields]:
|
||||
|
|
|
|||
7
frappe/core/doctype/doctype/patches/set_route.py
Normal file
7
frappe/core/doctype/doctype/patches/set_route.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import frappe
|
||||
from frappe.desk.utils import get_doctype_route
|
||||
|
||||
def execute():
|
||||
for doctype in frappe.get_all('DocType', ['name', 'route'], dict(istable=0)):
|
||||
if not doctype.route:
|
||||
frappe.db.set_value('DocType', doctype.name, 'route', get_doctype_route(doctype.name), update_modified = False)
|
||||
|
|
@ -23,7 +23,7 @@ class NavbarSettings(Document):
|
|||
if not frappe.flags.in_patch and (len(before_save_items) > len(after_save_items)):
|
||||
frappe.throw(_("Please hide the standard navbar items instead of deleting them"))
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_app_logo():
|
||||
app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo')
|
||||
if not app_logo:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
"two_factor_auth",
|
||||
"navigation_settings_section",
|
||||
"search_bar",
|
||||
"notification",
|
||||
"notifications",
|
||||
"chat",
|
||||
"list_settings_section",
|
||||
"list_sidebar",
|
||||
|
|
@ -84,12 +84,6 @@
|
|||
"fieldtype": "Check",
|
||||
"label": "Search Bar"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "notification",
|
||||
"fieldtype": "Check",
|
||||
"label": "Notification"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "chat",
|
||||
|
|
@ -141,13 +135,19 @@
|
|||
"fieldname": "view_switcher",
|
||||
"fieldtype": "Check",
|
||||
"label": "View Switcher"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "notifications",
|
||||
"fieldtype": "Check",
|
||||
"label": "Notifications"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-bookmark",
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-11 17:29:13.149522",
|
||||
"modified": "2020-12-03 14:08:38.181035",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Role",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import frappe
|
|||
|
||||
from frappe.model.document import Document
|
||||
|
||||
desk_properties = ("search_bar", "notification", "chat", "list_sidebar",
|
||||
desk_properties = ("search_bar", "notifications", "chat", "list_sidebar",
|
||||
"bulk_actions", "view_switcher", "form_sidebar", "timeline", "dashboard")
|
||||
|
||||
class Role(Document):
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class UserPermission(Document):
|
|||
ref_link = frappe.get_desk_link(self.doctype, overlap_exists[0].name)
|
||||
frappe.throw(_("{0} has already assigned default value for {1}.").format(ref_link, self.allow))
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_user_permissions(user=None):
|
||||
'''Get all users permissions for the user as a dict of doctype'''
|
||||
# if this is called from client-side,
|
||||
|
|
@ -66,7 +66,7 @@ def get_user_permissions(user=None):
|
|||
if not user:
|
||||
user = frappe.session.user
|
||||
|
||||
if not user or user == "Administrator":
|
||||
if not user or user in ("Administrator", "Guest"):
|
||||
return {}
|
||||
|
||||
cached_user_permissions = frappe.cache().hget("user_permissions", user)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"document_type",
|
||||
"route",
|
||||
"fields",
|
||||
"client_script"
|
||||
],
|
||||
|
|
@ -31,11 +32,17 @@
|
|||
"fieldname": "client_script",
|
||||
"fieldtype": "Code",
|
||||
"label": "Client Script"
|
||||
},
|
||||
{
|
||||
"fieldname": "route",
|
||||
"fieldtype": "Data",
|
||||
"label": "Route",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-17 15:49:49.669291",
|
||||
"modified": "2020-12-10 15:01:04.352184",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "DocType Layout",
|
||||
|
|
@ -52,8 +59,13 @@
|
|||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Guest"
|
||||
}
|
||||
],
|
||||
"route": "doctype-layout",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ from __future__ import unicode_literals
|
|||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
from frappe.desk.utils import get_doctype_route
|
||||
|
||||
class DocTypeLayout(Document):
|
||||
def validate(self):
|
||||
frappe.cache().delete_value('doctype_name_map')
|
||||
if not self.route:
|
||||
self.route = get_doctype_route(self.name)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import frappe
|
||||
|
||||
def execute():
|
||||
for web_form_name in frappe.db.get_all('Web Form', pluck='name'):
|
||||
web_form = frappe.get_doc('Web Form', web_form_name)
|
||||
doctype_layout = frappe.get_doc(dict(
|
||||
doctype = 'DocType Layout',
|
||||
document_type = web_form.doc_type,
|
||||
name = web_form.title,
|
||||
route = web_form.route,
|
||||
fields = [dict(fieldname = d.fieldname, label=d.label) for d in web_form.web_form_fields if d.fieldname]
|
||||
)).insert()
|
||||
print(doctype_layout.name)
|
||||
|
|
@ -13,7 +13,7 @@ from frappe.desk.form.document_follow import is_document_followed
|
|||
from frappe import _
|
||||
from six.moves.urllib.parse import quote
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def getdoc(doctype, name, user=None):
|
||||
"""
|
||||
Loads a doclist for a given document. This method is called directly from the client.
|
||||
|
|
@ -52,7 +52,7 @@ def getdoc(doctype, name, user=None):
|
|||
|
||||
frappe.response.docs.append(doc)
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def getdoctype(doctype, with_parent=False, cached_timestamp=None):
|
||||
"""load doctype"""
|
||||
|
||||
|
|
|
|||
|
|
@ -202,13 +202,17 @@ class FormMeta(Meta):
|
|||
self.load_kanban_column_fields()
|
||||
|
||||
def load_kanban_column_fields(self):
|
||||
values = frappe.get_list(
|
||||
'Kanban Board', fields=['field_name'],
|
||||
filters={'reference_doctype': self.name})
|
||||
try:
|
||||
values = frappe.get_list(
|
||||
'Kanban Board', fields=['field_name'],
|
||||
filters={'reference_doctype': self.name})
|
||||
|
||||
fields = [x['field_name'] for x in values]
|
||||
fields = list(set(fields))
|
||||
self.set("__kanban_column_fields", fields, as_value=True)
|
||||
fields = [x['field_name'] for x in values]
|
||||
fields = list(set(fields))
|
||||
self.set("__kanban_column_fields", fields, as_value=True)
|
||||
except frappe.PermissionError:
|
||||
# no access to kanban board
|
||||
pass
|
||||
|
||||
def get_code_files_via_hooks(hook, name):
|
||||
code_files = []
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from __future__ import unicode_literals
|
|||
|
||||
import frappe
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_list_settings(doctype):
|
||||
try:
|
||||
return frappe.get_cached_doc("List View Settings", doctype)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from frappe.core.doctype.access_log.access_log import make_access_log
|
|||
from frappe.utils import cstr, format_duration
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
@frappe.read_only()
|
||||
def get():
|
||||
args = get_form_params()
|
||||
|
|
|
|||
|
|
@ -3,26 +3,5 @@
|
|||
|
||||
import frappe
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_doctype_name(name):
|
||||
# translates the doctype name from url to name `sales-order` to `Sales Order`
|
||||
# also supports document type layouts
|
||||
# if with_layout is set: return the layout object too
|
||||
|
||||
def get_name_map():
|
||||
name_map = {}
|
||||
for d in frappe.get_all('DocType'):
|
||||
name_map[d.name.lower().replace(' ', '-')] = frappe._dict(doctype = d.name)
|
||||
|
||||
for d in frappe.get_all('DocType Layout', fields = ['name', 'document_type']):
|
||||
name_map[d.name.lower().replace(' ', '-')] = frappe._dict(doctype = d.document_type, doctype_layout = d.name)
|
||||
|
||||
return name_map
|
||||
|
||||
data = frappe._dict(name_map = frappe.cache().get_value('doctype_name_map', get_name_map).get(name, dict(doctype = name)))
|
||||
|
||||
if data.name_map.get('doctype_layout'):
|
||||
# return the layout object
|
||||
frappe.response.docs.append(frappe.get_doc('DocType Layout', data.name_map.get('doctype_layout')).as_dict())
|
||||
|
||||
return data
|
||||
def get_doctype_route(name):
|
||||
return name.lower().replace(' ', '-')
|
||||
|
|
@ -35,13 +35,9 @@
|
|||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.717 7c2.29 0 4.211 1.859 4.494 4.266 1.272.152 2.289 1.31 2.289 2.742 0 1.523-1.13 2.742-2.543 2.742H8.043c-1.413 0-2.543-1.219-2.543-2.742 0-1.188.707-2.224 1.724-2.59C7.422 8.92 9.372 7 11.717 7zm.148 2.37a.499.499 0 0 0-.363.156l-1.556 1.555a.5.5 0 1 0 .708.707l.71-.711v3.097a.5.5 0 0 0 1 0v-3.098l.713.712a.5.5 0 1 0 .707-.707l-1.565-1.565a.498.498 0 0 0-.354-.146z"
|
||||
fill="#fff"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" id="icon-upload">
|
||||
<path d="M10.2427 2.3999V11.7332" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.29004 5.35228L10.2424 2.3999L13.1948 5.35228" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<mask id="path-3-inside-1" fill="white">
|
||||
<path d="M13.9334 8.30469H16.8858V15.8999C16.8858 17.0045 15.9904 17.8999 14.8858 17.8999H5.6001C4.49553 17.8999 3.6001 17.0045 3.6001 15.8999V8.30469H6.55248"/>
|
||||
</mask>
|
||||
<path d="M16.8858 8.30469H17.8858C17.8858 7.7524 17.4381 7.30469 16.8858 7.30469V8.30469ZM3.6001 8.30469V7.30469C3.04781 7.30469 2.6001 7.7524 2.6001 8.30469H3.6001ZM13.9334 9.30469H16.8858V7.30469H13.9334V9.30469ZM15.8858 8.30469V15.8999H17.8858V8.30469H15.8858ZM14.8858 16.8999H5.6001V18.8999H14.8858V16.8999ZM4.6001 15.8999V8.30469H2.6001V15.8999H4.6001ZM3.6001 9.30469H6.55248V7.30469H3.6001V9.30469ZM5.6001 16.8999C5.04781 16.8999 4.6001 16.4522 4.6001 15.8999H2.6001C2.6001 17.5568 3.94325 18.8999 5.6001 18.8999V16.8999ZM15.8858 15.8999C15.8858 16.4522 15.4381 16.8999 14.8858 16.8999V18.8999C16.5427 18.8999 17.8858 17.5568 17.8858 15.8999H15.8858Z" fill="white" mask="url(#path-3-inside-1)"/>
|
||||
<symbol viewBox="0 0 20 20" id="icon-upload" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.596 2.046a.5.5 0 0 0-.707 0L6.937 5a.5.5 0 0 0 .707.707l2.099-2.099v8.126a.5.5 0 1 0 1 0V3.607l2.098 2.099a.5.5 0 0 0 .708-.707l-2.953-2.953z"/>
|
||||
<path d="M6.552 8.305v1H4.6V15.9a1 1 0 0 0 1 1h9.286a1 1 0 0 0 1-1V9.305h-1.953v-1h2.953V15.9a2 2 0 0 1-2 2H5.6a2 2 0 0 1-2-2V8.305h2.952z"/>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-tag">
|
||||
<path d="M12.6401 10.2571L10.107 12.7901C9.52125 13.3759 8.5718 13.3756 7.98601 12.7898L2.49654 7.30037C2.40278 7.2066 2.3501 7.07942 2.3501 6.94682L2.3501 3C2.3501 2.72386 2.57396 2.5 2.8501 2.5L6.79691 2.5C6.92952 2.5 7.0567 2.55268 7.15047 2.64645L12.6399 8.13591C13.2257 8.7217 13.2259 9.67131 12.6401 10.2571Z" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
|
@ -660,4 +656,12 @@
|
|||
<path d="M8.54541 9.74542L4.90908 9.74542" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
<path d="M8.54541 12.6545L4.90908 12.6545" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="square"/>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-sidebar-collapse">
|
||||
<path d="M12 6L6 12L12 18" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M18 6L12 12L18 18" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-sidebar-expand">
|
||||
<path d="M12 18L18 12L12 6" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 18L12 12L6 6" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
|
@ -2670,20 +2670,6 @@ frappe.chat.render = (render = true, force = false) =>
|
|||
// With the assumption, that there's only one navbar.
|
||||
const $placeholder = $('.navbar .frappe-chat-dropdown')
|
||||
|
||||
// Render if frappe-chat-toggle doesn't exist.
|
||||
if ( frappe.utils.is_empty($placeholder.has('.frappe-chat-toggle')) ) {
|
||||
const $template = $(`
|
||||
<a class="dropdown-toggle frappe-chat-toggle" data-toggle="dropdown">
|
||||
<div>
|
||||
<i class="octicon octicon-comment-discussion"/>
|
||||
</div>
|
||||
</a>
|
||||
`)
|
||||
|
||||
$placeholder.addClass('dropdown hidden')
|
||||
$placeholder.html($template)
|
||||
}
|
||||
|
||||
if ( render ) {
|
||||
$placeholder.removeClass('hidden')
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -160,8 +160,6 @@ frappe.Application = Class.extend({
|
|||
}, 600000); // check every 10 minutes
|
||||
}
|
||||
}
|
||||
|
||||
this.fetch_tags();
|
||||
},
|
||||
|
||||
set_route() {
|
||||
|
|
@ -170,7 +168,7 @@ frappe.Application = Class.extend({
|
|||
localStorage.removeItem("session_last_route");
|
||||
} else {
|
||||
// route to home page
|
||||
frappe.route();
|
||||
frappe.router.route();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -263,6 +261,7 @@ frappe.Application = Class.extend({
|
|||
this.check_metadata_cache_status();
|
||||
this.set_globals();
|
||||
this.sync_pages();
|
||||
frappe.router.setup();
|
||||
moment.locale("en");
|
||||
moment.user_utc_offset = moment().utcOffset();
|
||||
if(frappe.boot.timezone_info) {
|
||||
|
|
@ -272,6 +271,7 @@ frappe.Application = Class.extend({
|
|||
frappe.dom.set_style(frappe.boot.print_css, "print-style");
|
||||
}
|
||||
frappe.user.name = frappe.boot.user.name;
|
||||
frappe.router.setup();
|
||||
} else {
|
||||
this.set_as_guest();
|
||||
}
|
||||
|
|
@ -294,6 +294,7 @@ frappe.Application = Class.extend({
|
|||
|
||||
set_globals: function() {
|
||||
frappe.session.user = frappe.boot.user.name;
|
||||
frappe.session.logged_in_user = frappe.boot.user.name;
|
||||
frappe.session.user_email = frappe.boot.user.email;
|
||||
frappe.session.user_fullname = frappe.user_info().fullname;
|
||||
|
||||
|
|
@ -599,10 +600,6 @@ frappe.Application = Class.extend({
|
|||
frappe.show_alert(message);
|
||||
});
|
||||
},
|
||||
|
||||
fetch_tags() {
|
||||
frappe.tags.utils.fetch_tags();
|
||||
}
|
||||
});
|
||||
|
||||
frappe.get_module = function(m, default_module) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
// add_fetches
|
||||
import Awesomplete from 'awesomplete';
|
||||
|
||||
frappe.ui.form.recent_link_validations = {};
|
||||
|
||||
frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
||||
make_input: function() {
|
||||
var me = this;
|
||||
|
|
@ -439,40 +441,44 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
this.docname, value);
|
||||
},
|
||||
validate_link_and_fetch: function(df, doctype, docname, value) {
|
||||
var me = this;
|
||||
|
||||
if(value) {
|
||||
return new Promise((resolve) => {
|
||||
var fetch = '';
|
||||
|
||||
if(this.frm && this.frm.fetch_dict[df.fieldname]) {
|
||||
fetch = this.frm.fetch_dict[df.fieldname].columns.join(', ');
|
||||
}
|
||||
|
||||
return frappe.call({
|
||||
method:'frappe.desk.form.utils.validate_link',
|
||||
type: "GET",
|
||||
args: {
|
||||
'value': value,
|
||||
'options': doctype,
|
||||
'fetch': fetch
|
||||
},
|
||||
no_spinner: true,
|
||||
callback: function(r) {
|
||||
if(r.message=='Ok') {
|
||||
if(r.fetch_values && docname) {
|
||||
me.set_fetch_values(df, docname, r.fetch_values);
|
||||
}
|
||||
resolve(r.valid_value);
|
||||
} else {
|
||||
resolve("");
|
||||
}
|
||||
}
|
||||
});
|
||||
// if default and no fetch, no need to validate
|
||||
if (!fetch && df.__default_value && df.__default_value===value) return value;
|
||||
|
||||
this.fetch_and_validate_link(resolve, df, doctype, docname, value, fetch);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
fetch_and_validate_link(resolve, df, doctype, docname, value, fetch) {
|
||||
frappe.call({
|
||||
method:'frappe.desk.form.utils.validate_link',
|
||||
type: "GET",
|
||||
args: {
|
||||
'value': value,
|
||||
'options': doctype,
|
||||
'fetch': fetch
|
||||
},
|
||||
no_spinner: true,
|
||||
callback: (r) => {
|
||||
if(r.message=='Ok') {
|
||||
if(r.fetch_values && docname) {
|
||||
this.set_fetch_values(df, docname, r.fetch_values);
|
||||
}
|
||||
resolve(r.valid_value);
|
||||
} else {
|
||||
resolve("");
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
set_fetch_values: function(df, docname, fetch_values) {
|
||||
var fl = this.frm.fetch_dict[df.fieldname].fields;
|
||||
for(var i=0; i < fl.length; i++) {
|
||||
|
|
|
|||
|
|
@ -1,92 +1,101 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
frappe.ui.form.Dashboard = Class.extend({
|
||||
init: function(opts) {
|
||||
frappe.ui.form.Dashboard = class FormDashboard {
|
||||
constructor(opts) {
|
||||
$.extend(this, opts);
|
||||
this.section = this.frm.fields_dict._form_dashboard.wrapper;
|
||||
this.parent = this.section.find('.section-body');
|
||||
this.wrapper = $(frappe.render_template('form_dashboard',
|
||||
{frm: this.frm})).appendTo(this.parent);
|
||||
this.setup_dashboard_sections();
|
||||
}
|
||||
|
||||
this.progress_area = this.wrapper.find(".progress-area");
|
||||
this.heatmap_area = this.wrapper.find('.form-heatmap');
|
||||
this.chart_area = this.wrapper.find('.form-graph');
|
||||
this.stats_area = this.wrapper.find('.form-stats');
|
||||
this.stats_area_row = this.stats_area.find('.row');
|
||||
this.links_area = this.wrapper.find('.form-links');
|
||||
this.transactions_area = this.links_area.find('.transactions');
|
||||
setup_dashboard_sections() {
|
||||
this.progress_area = new Section(this.parent, {
|
||||
css_class: 'progress-area',
|
||||
hidden: 1,
|
||||
collapsible: 1
|
||||
});
|
||||
|
||||
},
|
||||
reset: function() {
|
||||
this.heatmap_area = new Section(this.parent, {
|
||||
title: __("Overview"),
|
||||
css_class: 'form-heatmap',
|
||||
hidden: 1,
|
||||
collapsible: 1,
|
||||
body_html: `
|
||||
<div id="heatmap-${frappe.model.scrub(this.frm.doctype)}" class="heatmap"></div>
|
||||
<div class="text-muted small heatmap-message hidden"></div>
|
||||
`
|
||||
});
|
||||
|
||||
this.chart_area = new Section(this.parent, {
|
||||
title: __("Graph"),
|
||||
css_class: 'form-graph',
|
||||
hidden: 1,
|
||||
collapsible: 1
|
||||
});
|
||||
|
||||
this.stats_area_row = $(`<div class="row"></div>`);
|
||||
this.stats_area = new Section(this.parent, {
|
||||
title: __("Stats"),
|
||||
css_class: 'form-stats',
|
||||
hidden: 1,
|
||||
collapsible: 1,
|
||||
body_html: this.stats_area_row
|
||||
});
|
||||
|
||||
this.transactions_area = $(`<div class="transactions"></div`);
|
||||
this.links_area = new Section(this.parent, {
|
||||
title: __("Documents Links"),
|
||||
css_class: 'form-links',
|
||||
hidden: 1,
|
||||
collapsible: 1,
|
||||
body_html: this.transactions_area
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.hide();
|
||||
this.clear_headline();
|
||||
|
||||
// clear progress
|
||||
this.progress_area.empty().addClass('hidden');
|
||||
this.progress_area.body.empty();
|
||||
this.progress_area.hide();
|
||||
|
||||
// clear links
|
||||
this.links_area.addClass('hidden');
|
||||
this.links_area.find('.count, .open-notification').addClass('hidden');
|
||||
this.links_area.body.find('.count, .open-notification').addClass('hidden');
|
||||
this.links_area.hide();
|
||||
|
||||
// clear stats
|
||||
this.stats_area.addClass('hidden')
|
||||
this.stats_area_row.empty();
|
||||
this.stats_area.hide();
|
||||
|
||||
// clear custom
|
||||
this.wrapper.find('.custom').remove();
|
||||
this.parent.find('.custom').remove();
|
||||
this.hide();
|
||||
},
|
||||
set_headline: function(html, color) {
|
||||
this.frm.layout.show_message(html, color);
|
||||
},
|
||||
clear_headline: function() {
|
||||
this.frm.layout.show_message();
|
||||
},
|
||||
}
|
||||
|
||||
add_comment: function(text, alert_class, permanent) {
|
||||
var me = this;
|
||||
this.set_headline_alert(text, alert_class);
|
||||
if(!permanent) {
|
||||
setTimeout(function() {
|
||||
me.clear_headline();
|
||||
}, 10000);
|
||||
}
|
||||
},
|
||||
add_section(body_html, title=null, css_class="custom", hidden=false) {
|
||||
let options = {
|
||||
title,
|
||||
css_class,
|
||||
hidden,
|
||||
body_html,
|
||||
make_card: true,
|
||||
collapsible: 1
|
||||
};
|
||||
return new Section(this.parent, options).body;
|
||||
}
|
||||
|
||||
clear_comment: function() {
|
||||
this.clear_headline();
|
||||
},
|
||||
add_progress(title, percent, message) {
|
||||
let progress_chart = this.make_progress_chart(title);
|
||||
|
||||
set_headline_alert: function(text, color) {
|
||||
if(text) {
|
||||
this.set_headline(`<div>${text}</div>`, color);
|
||||
} else {
|
||||
this.clear_headline();
|
||||
}
|
||||
},
|
||||
|
||||
add_section: function(html, section_head=null) {
|
||||
let section = $(`<div class="form-dashboard-section custom"></div>`);
|
||||
if (section_head) {
|
||||
section.append(`<div class="section-head">${section_head}</div>`);
|
||||
}
|
||||
section.append(html);
|
||||
section.appendTo(this.wrapper);
|
||||
return section;
|
||||
},
|
||||
|
||||
add_progress: function(title, percent, message) {
|
||||
var progress_chart = this.make_progress_chart(title);
|
||||
|
||||
if(!$.isArray(percent)) {
|
||||
if (!$.isArray(percent)) {
|
||||
percent = this.format_percent(title, percent);
|
||||
}
|
||||
|
||||
var progress = $('<div class="progress"></div>').appendTo(progress_chart);
|
||||
let progress = $('<div class="progress"></div>').appendTo(progress_chart);
|
||||
|
||||
$.each(percent, function(i, opts) {
|
||||
$(repl('<div class="progress-bar %(progress_class)s" style="width: %(width)s" \
|
||||
title="%(title)s"></div>', opts)).appendTo(progress);
|
||||
$(`<div class="progress-bar ${opts.progress_class}" style="width: ${opts.width}" title="${opts.title}"></div>`).appendTo(progress);
|
||||
});
|
||||
|
||||
if (!message) message = '';
|
||||
|
|
@ -95,9 +104,9 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
this.show();
|
||||
|
||||
return progress_chart;
|
||||
},
|
||||
}
|
||||
|
||||
show_progress: function(title, percent, message) {
|
||||
show_progress(title, percent, message) {
|
||||
this._progress_map = this._progress_map || {};
|
||||
let progress_chart = this._progress_map[title];
|
||||
// create a new progress chart if it doesnt exist
|
||||
|
|
@ -119,19 +128,19 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
|
||||
if (!message) message = '';
|
||||
progress_chart.find('.progress-message').text(message);
|
||||
},
|
||||
}
|
||||
|
||||
hide_progress: function(title) {
|
||||
if (title){
|
||||
hide_progress(title) {
|
||||
if (title) {
|
||||
this._progress_map[title].remove();
|
||||
delete this._progress_map[title];
|
||||
} else {
|
||||
this._progress_map = {};
|
||||
this.progress_area.empty();
|
||||
this.progress_area.hide();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
format_percent: function(title, percent) {
|
||||
format_percent(title, percent) {
|
||||
const percentage = cint(percent);
|
||||
const width = percentage < 0 ? 100 : percentage;
|
||||
const progress_class = percentage < 0 ? "progress-bar-danger" : "progress-bar-success";
|
||||
|
|
@ -141,28 +150,30 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
width: width + '%',
|
||||
progress_class: progress_class
|
||||
}];
|
||||
},
|
||||
make_progress_chart: function(title) {
|
||||
var progress_chart = $('<div class="progress-chart" title="'+(title || '')+'"></div>')
|
||||
.appendTo(this.progress_area.removeClass('hidden'));
|
||||
return progress_chart;
|
||||
},
|
||||
}
|
||||
|
||||
refresh: function() {
|
||||
make_progress_chart(title) {
|
||||
this.progress_area.show();
|
||||
var progress_chart = $('<div class="progress-chart" title="'+(title || '')+'"></div>')
|
||||
.appendTo(this.progress_area.body);
|
||||
return progress_chart;
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.reset();
|
||||
if(this.frm.doc.__islocal) {
|
||||
if (this.frm.doc.__islocal || !frappe.boot.desk_settings.form_dashboard) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.data) {
|
||||
if (!this.data) {
|
||||
this.init_data();
|
||||
}
|
||||
|
||||
var show = false;
|
||||
|
||||
if(this.data && ((this.data.transactions || []).length
|
||||
if (this.data && ((this.data.transactions || []).length
|
||||
|| (this.data.reports || []).length)) {
|
||||
if(this.data.docstatus && this.frm.doc.docstatus !== this.data.docstatus) {
|
||||
if (this.data.docstatus && this.frm.doc.docstatus !== this.data.docstatus) {
|
||||
// limited docstatus
|
||||
return;
|
||||
}
|
||||
|
|
@ -171,53 +182,53 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
show = true;
|
||||
}
|
||||
|
||||
if(this.data.heatmap) {
|
||||
if (this.data.heatmap) {
|
||||
this.render_heatmap();
|
||||
show = true;
|
||||
}
|
||||
|
||||
if(this.data.graph) {
|
||||
if (this.data.graph) {
|
||||
this.setup_graph();
|
||||
// show = true;
|
||||
}
|
||||
|
||||
if(show) {
|
||||
if (show) {
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
after_refresh: function() {
|
||||
after_refresh() {
|
||||
var me = this;
|
||||
// show / hide new buttons (if allowed)
|
||||
this.links_area.find('.btn-new').each(function() {
|
||||
if(me.frm.can_create($(this).attr('data-doctype'))) {
|
||||
this.links_area.body.find('.btn-new').each(function() {
|
||||
if (me.frm.can_create($(this).attr('data-doctype'))) {
|
||||
$(this).removeClass('hidden');
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
init_data: function() {
|
||||
init_data() {
|
||||
this.data = this.frm.meta.__dashboard || {};
|
||||
if(!this.data.transactions) this.data.transactions = [];
|
||||
if(!this.data.internal_links) this.data.internal_links = {};
|
||||
if (!this.data.transactions) this.data.transactions = [];
|
||||
if (!this.data.internal_links) this.data.internal_links = {};
|
||||
this.filter_permissions();
|
||||
},
|
||||
}
|
||||
|
||||
add_transactions: function(opts) {
|
||||
add_transactions(opts) {
|
||||
// add additional data on dashboard
|
||||
let group_added = [];
|
||||
|
||||
if(!Array.isArray(opts)) opts=[opts];
|
||||
if (!Array.isArray(opts)) opts=[opts];
|
||||
|
||||
if(!this.data) {
|
||||
if (!this.data) {
|
||||
this.init_data();
|
||||
}
|
||||
|
||||
if(this.data && (this.data.transactions || []).length) {
|
||||
if (this.data && (this.data.transactions || []).length) {
|
||||
// check if label already exists, add items to it
|
||||
this.data.transactions.map(group => {
|
||||
opts.map(d => {
|
||||
if(d.label == group.label) {
|
||||
if (d.label == group.label) {
|
||||
group_added.push(d.label);
|
||||
group.items.push(...d.items);
|
||||
}
|
||||
|
|
@ -226,80 +237,81 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
|
||||
// if label not already present, add new label and items under it
|
||||
opts.map(d => {
|
||||
if(!group_added.includes(d.label)) {
|
||||
if (!group_added.includes(d.label)) {
|
||||
this.data.transactions.push(d);
|
||||
}
|
||||
});
|
||||
|
||||
this.filter_permissions();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
filter_permissions: function() {
|
||||
filter_permissions() {
|
||||
// filter out transactions for which the user
|
||||
// does not have permission
|
||||
var transactions = [];
|
||||
let transactions = [];
|
||||
(this.data.transactions || []).forEach(function(group) {
|
||||
var items = [];
|
||||
let items = [];
|
||||
group.items.forEach(function(doctype) {
|
||||
if(frappe.model.can_read(doctype)) {
|
||||
if (frappe.model.can_read(doctype)) {
|
||||
items.push(doctype);
|
||||
}
|
||||
});
|
||||
|
||||
// only add thie group, if there is atleast
|
||||
// only add this group, if there is at-least
|
||||
// one item with permission
|
||||
if(items.length) {
|
||||
if (items.length) {
|
||||
group.items = items;
|
||||
transactions.push(group);
|
||||
}
|
||||
});
|
||||
this.data.transactions = transactions;
|
||||
},
|
||||
render_links: function() {
|
||||
}
|
||||
|
||||
render_links() {
|
||||
var me = this;
|
||||
this.links_area.removeClass('hidden');
|
||||
this.links_area.find('.btn-new').addClass('hidden');
|
||||
if(this.data_rendered) {
|
||||
this.links_area.show();
|
||||
this.links_area.body.find('.btn-new').addClass('hidden');
|
||||
if (this.data_rendered) {
|
||||
return;
|
||||
}
|
||||
|
||||
//this.transactions_area.empty();
|
||||
|
||||
this.data.frm = this.frm;
|
||||
|
||||
let transactions_area_body = this.transactions_area;
|
||||
|
||||
$(frappe.render_template('form_links', this.data))
|
||||
.appendTo(this.transactions_area)
|
||||
.appendTo(transactions_area_body);
|
||||
|
||||
if (this.data.reports && this.data.reports.length) {
|
||||
$(frappe.render_template('report_links', this.data))
|
||||
.appendTo(this.transactions_area)
|
||||
.appendTo(transactions_area_body);
|
||||
}
|
||||
|
||||
// bind links
|
||||
this.transactions_area.find(".badge-link").on('click', function() {
|
||||
transactions_area_body.find(".badge-link").on('click', function() {
|
||||
me.open_document_list($(this).parent());
|
||||
});
|
||||
|
||||
// bind reports
|
||||
this.transactions_area.find(".report-link").on('click', function() {
|
||||
transactions_area_body.find(".report-link").on('click', function() {
|
||||
me.open_report($(this).parent());
|
||||
});
|
||||
|
||||
// bind open notifications
|
||||
this.transactions_area.find('.open-notification').on('click', function() {
|
||||
transactions_area_body.find('.open-notification').on('click', function() {
|
||||
me.open_document_list($(this).parent(), true);
|
||||
});
|
||||
|
||||
// bind new
|
||||
this.transactions_area.find('.btn-new').on('click', function() {
|
||||
transactions_area_body.find('.btn-new').on('click', function() {
|
||||
me.frm.make_new($(this).attr('data-doctype'));
|
||||
});
|
||||
|
||||
this.data_rendered = true;
|
||||
},
|
||||
open_report: function($link) {
|
||||
}
|
||||
|
||||
open_report($link) {
|
||||
let report = $link.attr('data-report');
|
||||
|
||||
let fieldname = this.data.non_standard_fieldnames
|
||||
|
|
@ -308,28 +320,30 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
|
||||
frappe.route_options[fieldname] = this.frm.doc.name;
|
||||
frappe.set_route("query-report", report);
|
||||
},
|
||||
open_document_list: function($link, show_open) {
|
||||
}
|
||||
|
||||
open_document_list($link, show_open) {
|
||||
// show document list with filters
|
||||
var doctype = $link.attr('data-doctype'),
|
||||
names = $link.attr('data-names') || [];
|
||||
|
||||
if(this.data.internal_links[doctype]) {
|
||||
if(names.length) {
|
||||
if (this.data.internal_links[doctype]) {
|
||||
if (names.length) {
|
||||
frappe.route_options = {'name': ['in', names]};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if(this.data.fieldname) {
|
||||
} else if (this.data.fieldname) {
|
||||
frappe.route_options = this.get_document_filter(doctype);
|
||||
if(show_open) {
|
||||
if (show_open) {
|
||||
frappe.ui.notifications.show_open_count_list(doctype);
|
||||
}
|
||||
}
|
||||
|
||||
frappe.set_route("List", doctype, "List");
|
||||
},
|
||||
get_document_filter: function(doctype) {
|
||||
}
|
||||
|
||||
get_document_filter(doctype) {
|
||||
// return the default filter for the given document
|
||||
// like {"customer": frm.doc.name}
|
||||
var filter = {};
|
||||
|
|
@ -344,9 +358,10 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
|
||||
filter[fieldname] = this.frm.doc.name;
|
||||
return filter;
|
||||
},
|
||||
set_open_count: function() {
|
||||
if(!this.data.transactions || !this.data.fieldname) {
|
||||
}
|
||||
|
||||
set_open_count() {
|
||||
if (!this.data.transactions || !this.data.fieldname) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +370,9 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
me = this;
|
||||
|
||||
this.data.transactions.forEach(function(group) {
|
||||
group.items.forEach(function(item) { items.push(item); });
|
||||
group.items.forEach(function(item) {
|
||||
items.push(item);
|
||||
});
|
||||
});
|
||||
|
||||
var method = this.data.method || 'frappe.desk.notifications.get_open_count';
|
||||
|
|
@ -368,7 +385,7 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
items: items
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message.timeline_data) {
|
||||
if (r.message.timeline_data) {
|
||||
me.update_heatmap(r.message.timeline_data);
|
||||
}
|
||||
|
||||
|
|
@ -404,12 +421,13 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
}
|
||||
});
|
||||
|
||||
},
|
||||
set_badge_count: function(doctype, open_count, count, names) {
|
||||
}
|
||||
|
||||
set_badge_count(doctype, open_count, count, names) {
|
||||
var $link = $(this.transactions_area)
|
||||
.find('.document-link[data-doctype="'+doctype+'"]');
|
||||
|
||||
if(open_count) {
|
||||
if (open_count) {
|
||||
$link.find('.open-notification')
|
||||
.removeClass('hidden')
|
||||
.html((open_count > 99) ? '99+' : open_count);
|
||||
|
|
@ -421,24 +439,24 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
.text((count > 99) ? '99+' : count);
|
||||
}
|
||||
|
||||
if(this.data.internal_links[doctype]) {
|
||||
if(names && names.length) {
|
||||
if (this.data.internal_links[doctype]) {
|
||||
if (names && names.length) {
|
||||
$link.attr('data-names', names ? names.join(',') : '');
|
||||
} else {
|
||||
$link.find('a').attr('disabled', true);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
update_heatmap: function(data) {
|
||||
if(this.heatmap) {
|
||||
update_heatmap(data) {
|
||||
if (this.heatmap) {
|
||||
this.heatmap.update({dataPoints: data});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// heatmap
|
||||
render_heatmap: function() {
|
||||
if(!this.heatmap) {
|
||||
render_heatmap() {
|
||||
if (!this.heatmap) {
|
||||
this.heatmap = new frappe.Chart("#heatmap-" + frappe.model.scrub(this.frm.doctype), {
|
||||
type: 'heatmap',
|
||||
start: new Date(moment().subtract(1, 'year').toDate()),
|
||||
|
|
@ -449,32 +467,36 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
});
|
||||
|
||||
// center the heatmap
|
||||
this.heatmap_area.removeClass('hidden').find('svg').css({'margin': 'auto'});
|
||||
this.heatmap_area.show();
|
||||
this.heatmap_area.body.find('svg').css({'margin': 'auto'});
|
||||
|
||||
// message
|
||||
var heatmap_message = this.heatmap_area.find('.heatmap-message');
|
||||
if(this.data.heatmap_message) {
|
||||
var heatmap_message = this.heatmap_area.body.find('.heatmap-message');
|
||||
if (this.data.heatmap_message) {
|
||||
heatmap_message.removeClass('hidden').html(this.data.heatmap_message);
|
||||
} else {
|
||||
heatmap_message.addClass('hidden');
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
add_indicator: function(label, color) {
|
||||
add_indicator(label, color) {
|
||||
this.show();
|
||||
this.stats_area.removeClass('hidden');
|
||||
this.stats_area.show();
|
||||
|
||||
|
||||
// set colspan
|
||||
var indicators = this.stats_area_row.find('.indicator-column');
|
||||
var n_indicators = indicators.length + 1;
|
||||
var colspan;
|
||||
if(n_indicators > 4) { colspan = 3 }
|
||||
else { colspan = 12 / n_indicators; }
|
||||
if (n_indicators > 4) {
|
||||
colspan = 3;
|
||||
} else {
|
||||
colspan = 12 / n_indicators;
|
||||
}
|
||||
|
||||
// reset classes in existing indicators
|
||||
if(indicators.length) {
|
||||
if (indicators.length) {
|
||||
indicators.removeClass().addClass('col-sm-'+colspan).addClass('indicator-column');
|
||||
}
|
||||
|
||||
|
|
@ -482,10 +504,10 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
+label+'</span></div>').appendTo(this.stats_area_row);
|
||||
|
||||
return indicator;
|
||||
},
|
||||
}
|
||||
|
||||
// graphs
|
||||
setup_graph: function() {
|
||||
setup_graph() {
|
||||
var me = this;
|
||||
var method = this.data.graph_method;
|
||||
var args = {
|
||||
|
|
@ -500,7 +522,7 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
args: args,
|
||||
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
if (r.message) {
|
||||
me.render_graph(r.message);
|
||||
me.show();
|
||||
} else {
|
||||
|
|
@ -508,11 +530,11 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
render_graph: function(args) {
|
||||
var me = this;
|
||||
this.chart_area.empty().removeClass('hidden');
|
||||
render_graph(args) {
|
||||
this.chart_area.show();
|
||||
this.chart_area.body.empty();
|
||||
$.extend(args, {
|
||||
type: 'line',
|
||||
colors: ['green'],
|
||||
|
|
@ -524,21 +546,151 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
this.show();
|
||||
|
||||
this.chart = new frappe.Chart('.form-graph', args);
|
||||
if(!this.chart) {
|
||||
if (!this.chart) {
|
||||
this.hide();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
show: function() {
|
||||
show() {
|
||||
this.toggle_visibility(true);
|
||||
},
|
||||
}
|
||||
|
||||
hide: function() {
|
||||
hide() {
|
||||
this.toggle_visibility(false);
|
||||
},
|
||||
}
|
||||
|
||||
toggle_visibility(show) {
|
||||
this.section.toggleClass('visible-section', show);
|
||||
this.section.toggleClass('empty-section', !show);
|
||||
this.parent.toggleClass('visible-section', show);
|
||||
this.parent.toggleClass('empty-section', !show);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Review! code related to headline should be the part of layout/form
|
||||
set_headline(html, color) {
|
||||
this.frm.layout.show_message(html, color);
|
||||
}
|
||||
|
||||
clear_headline() {
|
||||
this.frm.layout.show_message();
|
||||
}
|
||||
|
||||
add_comment(text, alert_class, permanent) {
|
||||
var me = this;
|
||||
this.set_headline_alert(text, alert_class);
|
||||
if (!permanent) {
|
||||
setTimeout(function() {
|
||||
me.clear_headline();
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
clear_comment() {
|
||||
this.clear_headline();
|
||||
}
|
||||
|
||||
set_headline_alert(text, color) {
|
||||
if (text) {
|
||||
this.set_headline(`<div>${text}</div>`, color);
|
||||
} else {
|
||||
this.clear_headline();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Section {
|
||||
constructor(parent, options) {
|
||||
this.parent = parent;
|
||||
this.df = options || {};
|
||||
this.make();
|
||||
|
||||
if (this.df.title && this.df.collapsible) {
|
||||
this.collapse();
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
make() {
|
||||
this.wrapper = $(`<div class="form-dashboard-section ${ this.df.make_card ? "card-section" : "" }">`)
|
||||
.appendTo(this.parent);
|
||||
|
||||
if (this.df) {
|
||||
if (this.df.title) {
|
||||
this.make_head();
|
||||
}
|
||||
if (this.df.description) {
|
||||
this.description_wrapper = $(
|
||||
`<div class="col-sm-12 form-section-description">
|
||||
${__(this.df.description)}
|
||||
</div>`
|
||||
);
|
||||
|
||||
this.wrapper.append(this.description_wrapper);
|
||||
}
|
||||
if (this.df.css_class) {
|
||||
this.wrapper.addClass(this.df.css_class);
|
||||
}
|
||||
if (this.df.hide_border) {
|
||||
this.wrapper.toggleClass("hide-border", true);
|
||||
}
|
||||
}
|
||||
|
||||
this.body = $('<div class="section-body">').appendTo(this.wrapper);
|
||||
|
||||
if (this.df.body_html) {
|
||||
this.body.append(this.df.body_html);
|
||||
}
|
||||
}
|
||||
|
||||
make_head() {
|
||||
this.head = $(`
|
||||
<div class="section-head">
|
||||
${__(this.df.title)}
|
||||
<span class="ml-2 collapse-indicator mb-1"></span>
|
||||
</div>
|
||||
`);
|
||||
|
||||
this.head.appendTo(this.wrapper);
|
||||
this.indicator = this.head.find('.collapse-indicator');
|
||||
this.indicator.hide();
|
||||
|
||||
if (this.df.collapsible) {
|
||||
// show / hide based on status
|
||||
this.collapse_link = this.head.on("click", () => {
|
||||
this.collapse();
|
||||
});
|
||||
this.indicator.show();
|
||||
}
|
||||
}
|
||||
|
||||
refresh() {
|
||||
if (!this.df) return;
|
||||
|
||||
// hide if explicitly hidden
|
||||
let hide = this.df.hidden;
|
||||
this.wrapper.toggle(!hide);
|
||||
}
|
||||
|
||||
collapse(hide) {
|
||||
if (hide === undefined) {
|
||||
hide = !this.body.hasClass("hide");
|
||||
}
|
||||
|
||||
this.body.toggleClass("hide", hide);
|
||||
this.head && this.head.toggleClass("collapsed", hide);
|
||||
|
||||
let indicator_icon = hide ? 'down' : 'up-line';
|
||||
|
||||
this.indicator & this.indicator.html(frappe.utils.icon(indicator_icon, 'sm', 'mb-1'));
|
||||
}
|
||||
|
||||
is_collapsed() {
|
||||
return this.body.hasClass('hide');
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.wrapper.hide();
|
||||
}
|
||||
|
||||
show() {
|
||||
this.wrapper.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ frappe.ui.form.Footer = Class.extend({
|
|||
});
|
||||
},
|
||||
get_names_for_mentions() {
|
||||
let names_for_mentions = Object.keys(frappe.boot.user_info)
|
||||
let names_for_mentions = Object.keys(frappe.boot.user_info || [])
|
||||
.filter(user => {
|
||||
return !["Administrator", "Guest"].includes(user)
|
||||
&& frappe.boot.user_info[user].allowed_in_mentions;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
frappe.provide('frappe.ui.form');
|
||||
frappe.provide('frappe.model.docinfo');
|
||||
|
||||
import './quick_entry';
|
||||
import './toolbar';
|
||||
|
|
@ -23,13 +24,10 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.docname = '';
|
||||
this.doctype = doctype;
|
||||
this.doctype_layout_name = doctype_layout_name;
|
||||
if (doctype_layout_name) {
|
||||
this.doctype_layout = frappe.get_doc('DocType Layout', doctype_layout_name);
|
||||
}
|
||||
this.in_form = in_form ? true : false;
|
||||
|
||||
this.hidden = false;
|
||||
this.refresh_if_stale_for = 120;
|
||||
|
||||
var me = this;
|
||||
this.opendocs = {};
|
||||
this.custom_buttons = {};
|
||||
this.sections = [];
|
||||
|
|
@ -39,17 +37,8 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.pformat = {};
|
||||
this.fetch_dict = {};
|
||||
this.parent = parent;
|
||||
|
||||
this.doctype_layout = frappe.get_doc('DocType Layout', doctype_layout_name);
|
||||
this.setup_meta(doctype);
|
||||
|
||||
// show in form instead of in dialog, when called using url (router.js)
|
||||
this.in_form = in_form ? true : false;
|
||||
|
||||
// notify on rename
|
||||
$(document).on('rename', function(event, dt, old_name, new_name) {
|
||||
if(dt==me.doctype)
|
||||
me.rename_notify(dt, old_name, new_name);
|
||||
});
|
||||
}
|
||||
|
||||
setup_meta() {
|
||||
|
|
@ -107,7 +96,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.script_manager.setup();
|
||||
this.watch_model_updates();
|
||||
|
||||
if(!this.meta.hide_toolbar) {
|
||||
if(!this.meta.hide_toolbar && frappe.boot.desk_settings.timeline) {
|
||||
this.footer = new frappe.ui.form.Footer({
|
||||
frm: this,
|
||||
parent: $('<div>').appendTo(this.page.main.parent())
|
||||
|
|
@ -117,6 +106,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.setup_file_drop();
|
||||
this.setup_doctype_actions();
|
||||
this.setup_docinfo_change_listener();
|
||||
this.setup_notify_on_rename();
|
||||
|
||||
this.setup_done = true;
|
||||
}
|
||||
|
|
@ -175,6 +165,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
|
||||
this.dashboard = new frappe.ui.form.Dashboard({
|
||||
frm: this,
|
||||
parent: $('<div class="form-dashboard">').insertAfter(this.layout.wrapper.find('.form-message'))
|
||||
});
|
||||
|
||||
// workflow state
|
||||
|
|
@ -222,6 +213,13 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
});
|
||||
}
|
||||
|
||||
setup_notify_on_rename() {
|
||||
$(document).on('rename', (ev, dt, old_name, new_name) => {
|
||||
if(dt==this.doctype)
|
||||
this.rename_notify(dt, old_name, new_name);
|
||||
});
|
||||
}
|
||||
|
||||
setup_file_drop() {
|
||||
var me = this;
|
||||
this.$wrapper.on('dragenter dragover', false)
|
||||
|
|
@ -445,11 +443,13 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.layout.doc = this.doc;
|
||||
this.layout.attach_doc_and_docfields();
|
||||
|
||||
this.sidebar = new frappe.ui.form.Sidebar({
|
||||
frm: this,
|
||||
page: this.page
|
||||
});
|
||||
this.sidebar.make();
|
||||
if (frappe.boot.desk_settings.form_sidebar) {
|
||||
this.sidebar = new frappe.ui.form.Sidebar({
|
||||
frm: this,
|
||||
page: this.page
|
||||
});
|
||||
this.sidebar.make();
|
||||
}
|
||||
|
||||
// clear layout message
|
||||
this.layout.show_message();
|
||||
|
|
@ -1665,7 +1665,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
});
|
||||
|
||||
driver.defineSteps(steps);
|
||||
frappe.route.on('change', () => driver.reset());
|
||||
frappe.router.on('change', () => driver.reset());
|
||||
driver.start();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ frappe.form.formatters = {
|
|||
{onclick: docfield.link_onclick.replace(/"/g, '"'), value:value});
|
||||
} else if(docfield && doctype) {
|
||||
return `<a
|
||||
href="/app/form/${encodeURIComponent(frappe.router.slug(doctype))}/${encodeURIComponent(original_value)}"
|
||||
href="/app/${encodeURIComponent(frappe.router.slug(doctype))}/${encodeURIComponent(original_value)}"
|
||||
data-doctype="${doctype}"
|
||||
data-name="${original_value}">
|
||||
${__(options && options.label || value)}</a>`
|
||||
|
|
|
|||
|
|
@ -127,14 +127,6 @@ frappe.ui.form.Layout = Class.extend({
|
|||
if (this.no_opening_section()) {
|
||||
this.fields.unshift({fieldtype: 'Section Break'});
|
||||
}
|
||||
|
||||
this.fields.unshift({
|
||||
fieldtype: 'Section Break',
|
||||
fieldname: '_form_dashboard',
|
||||
cssClass: 'form-dashboard',
|
||||
collapsible: 1,
|
||||
// hidden: 1
|
||||
});
|
||||
},
|
||||
|
||||
replace_field: function(fieldname, df, render) {
|
||||
|
|
@ -312,10 +304,6 @@ frappe.ui.form.Layout = Class.extend({
|
|||
collapse = false;
|
||||
}
|
||||
|
||||
if (df.fieldname === '_form_dashboard') {
|
||||
collapse = localStorage.getItem('collapseFormDashboard')==='yes' ? true : false;
|
||||
}
|
||||
|
||||
section.collapse(collapse);
|
||||
}
|
||||
}
|
||||
|
|
@ -587,17 +575,13 @@ frappe.ui.form.Section = Class.extend({
|
|||
wrapper: this.wrapper
|
||||
};
|
||||
|
||||
if (this.df.collapsible && this.df.fieldname !== '_form_dashboard') {
|
||||
this.collapse(true);
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
},
|
||||
make: function() {
|
||||
if (!this.layout.page) {
|
||||
this.layout.page = $('<div class="form-page"></div>').appendTo(this.layout.wrapper);
|
||||
}
|
||||
let make_card = this.layout.card_layout && this.df.fieldname !== '_form_dashboard';
|
||||
let make_card = this.layout.card_layout;
|
||||
this.wrapper = $(`<div class="row form-section ${ make_card ? "card-section" : "" }">`)
|
||||
.appendTo(this.layout.page);
|
||||
this.layout.sections.push(this);
|
||||
|
|
@ -664,18 +648,12 @@ frappe.ui.form.Section = Class.extend({
|
|||
hide = !this.body.hasClass("hide");
|
||||
}
|
||||
|
||||
if (this.df.fieldname==='_form_dashboard') {
|
||||
localStorage.setItem('collapseFormDashboard', hide ? 'yes' : 'no');
|
||||
}
|
||||
|
||||
this.body.toggleClass("hide", hide);
|
||||
this.head.toggleClass("collapsed", hide);
|
||||
|
||||
let indicator_icon = hide ? 'down' : 'up-line';
|
||||
|
||||
this.indicator & this.indicator.html(frappe.utils.icon(indicator_icon, 'sm', 'mb-1'));
|
||||
// this.indicator && this.indicator.toggleClass("octicon-chevron-down", hide);
|
||||
// this.indicator && this.indicator.toggleClass("octicon-chevron-up", !hide);
|
||||
|
||||
// refresh signature fields
|
||||
this.fields_list.forEach((f) => {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ frappe.ui.form.Toolbar = Class.extend({
|
|||
}
|
||||
},
|
||||
set_title: function() {
|
||||
if(this.frm.meta.title_field) {
|
||||
if (this.frm.is_new()) {
|
||||
var title = __('New {0}', [this.frm.meta.name]);
|
||||
} else if (this.frm.meta.title_field) {
|
||||
let title_field = (this.frm.doc[this.frm.meta.title_field] || "").toString().trim();
|
||||
var title = strip_html(title_field || this.frm.docname);
|
||||
if(this.frm.doc.__islocal || title === this.frm.docname || this.frm.meta.autoname==="hash") {
|
||||
|
|
@ -198,30 +200,40 @@ frappe.ui.form.Toolbar = Class.extend({
|
|||
make_menu: function() {
|
||||
this.page.clear_icons();
|
||||
this.page.clear_menu();
|
||||
var me = this;
|
||||
var p = this.frm.perm[0];
|
||||
var docstatus = cint(this.frm.doc.docstatus);
|
||||
var is_submittable = frappe.model.is_submittable(this.frm.doc.doctype)
|
||||
var issingle = this.frm.meta.issingle;
|
||||
var print_settings = frappe.model.get_doc(":Print Settings", "Print Settings")
|
||||
var allow_print_for_draft = cint(print_settings.allow_print_for_draft);
|
||||
var allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled);
|
||||
|
||||
// Navigate
|
||||
if (!this.frm.is_new() && !issingle) {
|
||||
this.page.add_action_icon("left", function() {
|
||||
me.frm.navigate_records(1);
|
||||
}, 'prev-doc', __("Previous Document"));
|
||||
this.page.add_action_icon("right", function() {
|
||||
me.frm.navigate_records(0);
|
||||
}, 'next-doc', __("Next Document"));
|
||||
if (frappe.boot.desk_settings.form_sidebar) {
|
||||
this.make_navigation();
|
||||
this.make_menu_items();
|
||||
}
|
||||
},
|
||||
|
||||
make_navigation() {
|
||||
// Navigate
|
||||
if (!this.frm.is_new() && !this.frm.meta.issingle) {
|
||||
this.page.add_action_icon("left", () => {
|
||||
this.frm.navigate_records(1);
|
||||
}, 'prev-doc');
|
||||
this.page.add_action_icon("right", ()=> {
|
||||
this.frm.navigate_records(0);
|
||||
}, 'next-doc');
|
||||
}
|
||||
},
|
||||
|
||||
make_menu_items() {
|
||||
// Print
|
||||
const me = this;
|
||||
const p = this.frm.perm[0];
|
||||
const docstatus = cint(this.frm.doc.docstatus);
|
||||
const is_submittable = frappe.model.is_submittable(this.frm.doc.doctype)
|
||||
|
||||
const print_settings = frappe.model.get_doc(":Print Settings", "Print Settings")
|
||||
const allow_print_for_draft = cint(print_settings.allow_print_for_draft);
|
||||
const allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled);
|
||||
|
||||
if (!is_submittable || docstatus == 1 ||
|
||||
(allow_print_for_cancelled && docstatus == 2)||
|
||||
(allow_print_for_draft && docstatus == 0)) {
|
||||
if (frappe.model.can_print(null, me.frm) && !issingle) {
|
||||
if (frappe.model.can_print(null, me.frm) && !this.frm.meta.issingle) {
|
||||
this.page.add_menu_item(__("Print"), function() {
|
||||
me.frm.print_doc();
|
||||
}, true);
|
||||
|
|
@ -283,30 +295,7 @@ frappe.ui.form.Toolbar = Class.extend({
|
|||
});
|
||||
}
|
||||
|
||||
if (frappe.user_roles.includes("System Manager")) {
|
||||
let is_doctype_form = me.frm.doctype === 'DocType';
|
||||
let doctype = is_doctype_form ? me.frm.docname : me.frm.doctype;
|
||||
let is_doctype_custom = is_doctype_form ? me.frm.doc.custom : false;
|
||||
|
||||
if (doctype != 'DocType' && !is_doctype_custom && me.frm.meta.issingle === 0) {
|
||||
this.page.add_menu_item(__("Customize"), function() {
|
||||
if (me.frm.meta && me.frm.meta.custom) {
|
||||
frappe.set_route('Form', 'DocType', doctype);
|
||||
} else {
|
||||
frappe.set_route('Form', 'Customize Form', {
|
||||
doc_type: doctype
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
if (frappe.boot.developer_mode===1 && !is_doctype_form) {
|
||||
// edit doctype
|
||||
this.page.add_menu_item(__("Edit DocType"), function() {
|
||||
frappe.set_route('Form', 'DocType', me.frm.doctype);
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
this.make_customize_buttons();
|
||||
|
||||
// Auto Repeat
|
||||
if(this.can_repeat()) {
|
||||
|
|
@ -325,6 +314,35 @@ frappe.ui.form.Toolbar = Class.extend({
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
make_customize_buttons() {
|
||||
if (frappe.user_roles.includes("System Manager")) {
|
||||
let is_doctype_form = this.frm.doctype === 'DocType';
|
||||
let doctype = is_doctype_form ? this.frm.docname : this.frm.doctype;
|
||||
let is_doctype_custom = is_doctype_form ? this.frm.doc.custom : false;
|
||||
|
||||
if (doctype != 'DocType' && !is_doctype_custom && this.frm.meta.issingle === 0) {
|
||||
this.page.add_menu_item(__("Customize"), () => {
|
||||
if (this.frm.meta && this.frm.meta.custom) {
|
||||
frappe.set_route('Form', 'DocType', doctype);
|
||||
} else {
|
||||
frappe.set_route('Form', 'Customize Form', {
|
||||
doc_type: doctype
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
if (frappe.boot.developer_mode===1 && !is_doctype_form) {
|
||||
// edit doctype
|
||||
this.page.add_menu_item(__("Edit DocType"), () => {
|
||||
frappe.set_route('Form', 'DocType', this.frm.doctype);
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
can_repeat: function() {
|
||||
return this.frm.meta.allow_auto_repeat
|
||||
&& !this.frm.is_new()
|
||||
|
|
|
|||
|
|
@ -182,15 +182,17 @@ frappe.views.BaseList = class BaseList {
|
|||
'Dashboard': 'dashboard'
|
||||
}
|
||||
|
||||
this.views_menu = this.page.add_custom_button_group(__(`{0} View`, [this.view_name]), icon_map[this.view_name] || 'list');
|
||||
this.views_list = new frappe.views.Views({
|
||||
doctype: this.doctype,
|
||||
parent: this.views_menu,
|
||||
page: this.page,
|
||||
list_view: this,
|
||||
sidebar: this.list_sidebar,
|
||||
icon_map: icon_map
|
||||
});
|
||||
if (frappe.boot.desk_settings.view_switcher) {
|
||||
this.views_menu = this.page.add_custom_button_group(__(`{0} View`, [this.view_name]), icon_map[this.view_name] || 'list');
|
||||
this.views_list = new frappe.views.Views({
|
||||
doctype: this.doctype,
|
||||
parent: this.views_menu,
|
||||
page: this.page,
|
||||
list_view: this,
|
||||
sidebar: this.list_sidebar,
|
||||
icon_map: icon_map
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
set_default_secondary_action() {
|
||||
|
|
@ -236,7 +238,7 @@ frappe.views.BaseList = class BaseList {
|
|||
}
|
||||
|
||||
setup_side_bar() {
|
||||
if (this.hide_sidebar) return;
|
||||
if (this.hide_sidebar || !frappe.boot.desk_settings.list_sidebar) return;
|
||||
this.list_sidebar = new frappe.views.ListSidebar({
|
||||
doctype: this.doctype,
|
||||
stats: this.stats,
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ export default class ListFilter {
|
|||
}
|
||||
|
||||
get_list_filters() {
|
||||
if (frappe.session.user === 'Guest') return Promise.resolve();
|
||||
return frappe.db
|
||||
.get_list('List Filter', {
|
||||
fields: ['name', 'filter_name', 'for_user', 'filters'],
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
const doctype = route[1];
|
||||
|
||||
if (route.length === 2) {
|
||||
// List/{doctype} => List/{doctype}/{last_view} or List
|
||||
const user_settings = frappe.get_user_settings(doctype);
|
||||
const last_view = user_settings.last_view;
|
||||
frappe.set_route(
|
||||
|
|
@ -871,7 +870,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
? encodeURIComponent(doc.name)
|
||||
: doc.name;
|
||||
|
||||
return "/app/form/" + frappe.router.slug(frappe.router.doctype_layout || this.doctype) + "/" + docname;
|
||||
return `/app/${frappe.router.slug(frappe.router.doctype_layout || this.doctype)}/${docname}`;
|
||||
}
|
||||
|
||||
get_seen_class(doc) {
|
||||
|
|
@ -905,6 +904,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
let escaped_subject = frappe.utils.escape_html(subject);
|
||||
|
||||
const seen = this.get_seen_class(doc);
|
||||
console.log(this.get_form_link(doc));
|
||||
|
||||
let subject_html = `
|
||||
<input class="level-item list-row-checkbox hidden-xs" type="checkbox"
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ frappe.views.Views = class Views {
|
|||
}
|
||||
|
||||
set_route(view, calendar_name) {
|
||||
const route = ['list', frappe.router.doctype_layout || this.doctype, view];
|
||||
const route = [this.get_doctype_route(), 'view', view];
|
||||
if (calendar_name) route.push(calendar_name);
|
||||
frappe.set_route(route);
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ frappe.views.Views = class Views {
|
|||
if (item.name == frappe.utils.to_title_case(frappe.get_route().slice(-1)[0] || '')) {
|
||||
placeholder = item.name;
|
||||
}
|
||||
html += `<li><a class="dropdown-item" href="#${item.route}">${item.name}</a></li>`;
|
||||
html += `<li><a class="dropdown-item" href="/app/${item.route}">${item.name}</a></li>`;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ frappe.views.Views = class Views {
|
|||
reports.map((r) => {
|
||||
if (!r.ref_doctype || r.ref_doctype == this.doctype) {
|
||||
const report_type = r.report_type === 'Report Builder' ?
|
||||
`list/${r.ref_doctype}/report` : 'query-report';
|
||||
`/app/list/${r.ref_doctype}/report` : 'query-report';
|
||||
|
||||
const route = r.route || report_type + '/' + (r.title || r.name);
|
||||
|
||||
|
|
@ -233,11 +233,11 @@ frappe.views.Views = class Views {
|
|||
// has standard calendar view
|
||||
calendars.push({
|
||||
name: 'Default',
|
||||
route: `list/${this.doctype}/calendar/default`
|
||||
route: `/app/${this.get_doctype_route()}/view/calendar/default`
|
||||
});
|
||||
}
|
||||
result.map(calendar => {
|
||||
calendars.push({name: calendar.name, route: `list/${doctype}/calendar/${calendar.name}`});
|
||||
calendars.push({name: calendar.name, route: `/app/${this.get_doctype_route()}/view/calendar/${calendar.name}`});
|
||||
});
|
||||
|
||||
return calendars;
|
||||
|
|
@ -249,7 +249,7 @@ frappe.views.Views = class Views {
|
|||
let accounts = frappe.boot.email_accounts;
|
||||
accounts.forEach(account => {
|
||||
let email_account = (account.email_id == "All Accounts") ? "All Accounts" : account.email_account;
|
||||
let route = ["List", "Communication", "Inbox", email_account].join('/');
|
||||
let route = `/app/communication/inbox/${email_account}`;
|
||||
let display_name = ["All Accounts", "Sent Mail", "Spam", "Trash"].includes(account.email_id)
|
||||
? __(account.email_id)
|
||||
: account.email_account;
|
||||
|
|
@ -262,4 +262,8 @@ frappe.views.Views = class Views {
|
|||
|
||||
return accounts_to_add;
|
||||
}
|
||||
|
||||
get_doctype_route() {
|
||||
return frappe.router.slug(frappe.router.doctype_layout || this.doctype);
|
||||
}
|
||||
}
|
||||
|
|
@ -126,6 +126,7 @@ $.extend(frappe.model, {
|
|||
var user_permissions = frappe.defaults.get_user_permissions();
|
||||
let allowed_records = [];
|
||||
let default_doc = null;
|
||||
let value = null;
|
||||
if(user_permissions) {
|
||||
({allowed_records, default_doc} = frappe.perm.filter_allowed_docs_for_doctype(user_permissions[df.options], doc.doctype));
|
||||
}
|
||||
|
|
@ -139,71 +140,79 @@ $.extend(frappe.model, {
|
|||
if (df.fieldtype==="Link" && df.options!=="User") {
|
||||
// If user permission has Is Default enabled or single-user permission has found against respective doctype.
|
||||
if (has_user_permissions && default_doc) {
|
||||
return default_doc;
|
||||
}
|
||||
|
||||
if(!df.ignore_user_permissions) {
|
||||
value = default_doc;
|
||||
} else {
|
||||
// 2 - look in user defaults
|
||||
var user_defaults = frappe.defaults.get_user_defaults(df.options);
|
||||
if (user_defaults && user_defaults.length===1) {
|
||||
// Use User Permission value when only when it has a single value
|
||||
user_default = user_defaults[0];
|
||||
|
||||
if(!df.ignore_user_permissions) {
|
||||
var user_defaults = frappe.defaults.get_user_defaults(df.options);
|
||||
if (user_defaults && user_defaults.length===1) {
|
||||
// Use User Permission value when only when it has a single value
|
||||
user_default = user_defaults[0];
|
||||
}
|
||||
}
|
||||
|
||||
else if (!user_default) {
|
||||
user_default = frappe.defaults.get_user_default(df.fieldname);
|
||||
}
|
||||
|
||||
else if(!user_default && df.remember_last_selected_value && frappe.boot.user.last_selected_values) {
|
||||
user_default = frappe.boot.user.last_selected_values[df.options];
|
||||
}
|
||||
|
||||
var is_allowed_user_default = user_default &&
|
||||
(!has_user_permissions || allowed_records.includes(user_default));
|
||||
|
||||
// is this user default also allowed as per user permissions?
|
||||
if (is_allowed_user_default) {
|
||||
value = user_default;
|
||||
}
|
||||
}
|
||||
|
||||
if (!user_default) {
|
||||
user_default = frappe.defaults.get_user_default(df.fieldname);
|
||||
}
|
||||
|
||||
if(!user_default && df.remember_last_selected_value && frappe.boot.user.last_selected_values) {
|
||||
user_default = frappe.boot.user.last_selected_values[df.options];
|
||||
}
|
||||
|
||||
var is_allowed_user_default = user_default &&
|
||||
(!has_user_permissions || allowed_records.includes(user_default));
|
||||
|
||||
// is this user default also allowed as per user permissions?
|
||||
if (is_allowed_user_default) {
|
||||
return user_default;
|
||||
}
|
||||
}
|
||||
|
||||
// 3 - look in default of docfield
|
||||
if (df['default']) {
|
||||
if (!value || df['default']) {
|
||||
const default_val = String(df['default']);
|
||||
if (default_val == "__user" || default_val.toLowerCase() == "user") {
|
||||
return frappe.session.user;
|
||||
value = frappe.session.user;
|
||||
|
||||
} else if (default_val == "user_fullname") {
|
||||
return frappe.session.user_fullname;
|
||||
value = frappe.session.user_fullname;
|
||||
|
||||
} else if (default_val == "Today") {
|
||||
return frappe.datetime.get_today();
|
||||
value = frappe.datetime.get_today();
|
||||
|
||||
} else if ((default_val || "").toLowerCase() === "now") {
|
||||
return frappe.datetime.now_datetime();
|
||||
value = frappe.datetime.now_datetime();
|
||||
|
||||
} else if (default_val[0]===":") {
|
||||
var boot_doc = frappe.model.get_default_from_boot_docs(df, doc, parent_doc);
|
||||
var is_allowed_boot_doc = !has_user_permissions || allowed_records.includes(boot_doc);
|
||||
|
||||
if (is_allowed_boot_doc) {
|
||||
return boot_doc;
|
||||
value = boot_doc;
|
||||
}
|
||||
} else if (df.fieldname===meta.title_field) {
|
||||
// ignore defaults for title field
|
||||
return "";
|
||||
value = "";
|
||||
} else {
|
||||
// is this default value is also allowed as per user permissions?
|
||||
var is_allowed_default = !has_user_permissions || allowed_records.includes(df.default);
|
||||
if (df.fieldtype!=="Link" || df.options==="User" || is_allowed_default) {
|
||||
value = df["default"];
|
||||
}
|
||||
}
|
||||
|
||||
// is this default value is also allowed as per user permissions?
|
||||
var is_allowed_default = !has_user_permissions || allowed_records.includes(df.default);
|
||||
if (df.fieldtype!=="Link" || df.options==="User" || is_allowed_default) {
|
||||
return df["default"];
|
||||
}
|
||||
|
||||
} else if (df.fieldtype=="Time") {
|
||||
return frappe.datetime.now_time();
|
||||
value = frappe.datetime.now_time();
|
||||
}
|
||||
|
||||
// set it here so we know it was set as a default
|
||||
df.__default_value = value;
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
get_default_from_boot_docs: function(df, doc, parent_doc) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ $.extend(frappe.model.user_settings, {
|
|||
.then(r => JSON.parse(r.message || '{}'));
|
||||
},
|
||||
save: function(doctype, key, value) {
|
||||
if (frappe.session.user === 'Guest') return Promise.resolve();
|
||||
|
||||
const old_user_settings = frappe.model.user_settings[doctype] || {};
|
||||
const new_user_settings = $.extend(true, {}, old_user_settings); // deep copy
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ $.extend(frappe.model.user_settings, {
|
|||
return this.update(doctype, user_settings);
|
||||
},
|
||||
update: function(doctype, user_settings) {
|
||||
if (frappe.session.user === 'Guest') return Promise.resolve();
|
||||
return frappe.call({
|
||||
method: 'frappe.model.utils.user_settings.save',
|
||||
args: {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ frappe.provide('frappe.request.error_handlers');
|
|||
frappe.request.url = '/';
|
||||
frappe.request.ajax_count = 0;
|
||||
frappe.request.waiting_for_ajax = [];
|
||||
frappe.request.logs = {}
|
||||
|
||||
frappe.xcall = function(method, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
@ -89,6 +90,11 @@ frappe.call = function(opts) {
|
|||
delete args.cmd;
|
||||
}
|
||||
|
||||
// debouce if required
|
||||
if (opts.debounce && frappe.request.is_fresh(args, opts.debounce)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return frappe.request.call({
|
||||
type: opts.type || "POST",
|
||||
args: args,
|
||||
|
|
@ -127,7 +133,7 @@ frappe.request.call = function(opts) {
|
|||
message: __('The resource you are looking for is not available')});
|
||||
},
|
||||
403: function(xhr) {
|
||||
if (frappe.session.user === 'Guest') {
|
||||
if (frappe.session.logged_in_user !== 'Guest') {
|
||||
// session expired
|
||||
frappe.app.handle_session_expired();
|
||||
}
|
||||
|
|
@ -239,7 +245,7 @@ frappe.request.call = function(opts) {
|
|||
status_code_handler(data, xhr);
|
||||
}
|
||||
} catch(e) {
|
||||
console.log("Unable to handle success response"); // eslint-disable-line
|
||||
console.log("Unable to handle success response", data); // eslint-disable-line
|
||||
console.trace(e); // eslint-disable-line
|
||||
}
|
||||
|
||||
|
|
@ -278,6 +284,26 @@ frappe.request.call = function(opts) {
|
|||
});
|
||||
}
|
||||
|
||||
frappe.request.is_fresh = function(args, threshold) {
|
||||
// return true if a request with similar args has been sent recently
|
||||
if (!frappe.request.logs[args.cmd]) {
|
||||
frappe.request.logs[args.cmd] = [];
|
||||
}
|
||||
|
||||
for (let past_request of frappe.request.logs[args.cmd]) {
|
||||
// check if request has same args and was made recently
|
||||
if ((new Date() - past_request.timestamp) < threshold
|
||||
&& frappe.utils.deep_equal(args, past_request.args)) {
|
||||
console.log('throttled');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// log the request
|
||||
frappe.request.logs[args.cmd].push({args: args, timestamp: new Date()});
|
||||
return false;
|
||||
}
|
||||
|
||||
// call execute serverside request
|
||||
frappe.request.prepare = function(opts) {
|
||||
$("body").attr("data-ajax-state", "triggered");
|
||||
|
|
@ -322,7 +348,8 @@ frappe.request.cleanup = function(opts, r) {
|
|||
if(r) {
|
||||
|
||||
// session expired? - Guest has no business here!
|
||||
if (r.session_expired || frappe.session.user === "Guest") {
|
||||
if (r.session_expired ||
|
||||
(frappe.session.user === 'Guest' && frappe.session.logged_in_user !== "Guest")) {
|
||||
frappe.app.handle_session_expired();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,13 @@ $(window).on('hashchange', function() {
|
|||
let sub_path = frappe.router.get_sub_path(window.location.hash);
|
||||
window.location.hash = '';
|
||||
frappe.router.push_state(sub_path);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('popstate', () => {
|
||||
// forward-back button, just re-render based on current route
|
||||
frappe.route();
|
||||
frappe.router.route();
|
||||
});
|
||||
|
||||
// routing v2, capture all clicks so that the target is managed with push-state
|
||||
|
|
@ -52,18 +53,40 @@ $('body').on('click', 'a', function(e) {
|
|||
}
|
||||
|
||||
// target has "/app, this is a v2 style route.
|
||||
if (e.currentTarget.pathname &&
|
||||
(e.currentTarget.pathname.startsWith('/app') || e.currentTarget.pathname.startsWith('app'))) {
|
||||
if (e.currentTarget.pathname && frappe.router.is_app_route()) {
|
||||
return override(e, e.currentTarget.pathname);
|
||||
}
|
||||
});
|
||||
|
||||
frappe.router = {
|
||||
current_route: null,
|
||||
doctype_names: {},
|
||||
factory_views: ['form', 'list', 'report', 'tree', 'print'],
|
||||
routes: {},
|
||||
factory_views: ['form', 'list', 'report', 'tree', 'print', 'dashboard'],
|
||||
list_views: ['list', 'kanban', 'report', 'calendar', 'tree', 'gantt', 'dashboard', 'image', 'inbox'],
|
||||
layout_mapped: {},
|
||||
|
||||
is_app_route() {
|
||||
// desk paths must begin with /app or doctype route
|
||||
let path = window.location.pathname;
|
||||
if (path.substr(0, 1) === '/') path = path.substr(1);
|
||||
path = path.split('/');
|
||||
if (path[0]) {
|
||||
return path[0]==='app';
|
||||
}
|
||||
},
|
||||
|
||||
setup() {
|
||||
// setup the route names by forming slugs of the given doctypes
|
||||
for(let doctype of frappe.boot.user.can_read) {
|
||||
this.routes[this.slug(doctype)] = {doctype: doctype};
|
||||
}
|
||||
if (frappe.boot.doctype_layouts) {
|
||||
for (let doctype_layout of frappe.boot.doctype_layouts) {
|
||||
this.routes[this.slug(doctype_layout.name)] = {doctype: doctype_layout.document_type, doctype_layout: doctype_layout.name };
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
route() {
|
||||
// resolve the route from the URL or hash
|
||||
// translate it so the objects are well defined
|
||||
|
|
@ -71,64 +94,81 @@ frappe.router = {
|
|||
|
||||
if (!frappe.app) return;
|
||||
|
||||
let sub_path = frappe.router.get_sub_path();
|
||||
if (frappe.router.re_route(sub_path)) return;
|
||||
let sub_path = this.get_sub_path();
|
||||
if (this.re_route(sub_path)) return;
|
||||
|
||||
frappe.router.translate_doctype_name().then(() => {
|
||||
frappe.router.set_history(sub_path);
|
||||
|
||||
if (frappe.router.current_route[0]) {
|
||||
frappe.router.render_page();
|
||||
} else {
|
||||
// Show home
|
||||
frappe.views.pageview.show('');
|
||||
}
|
||||
|
||||
frappe.router.set_title();
|
||||
frappe.route.trigger('change');
|
||||
});
|
||||
this.current_route = this.parse();
|
||||
this.set_history(sub_path);
|
||||
this.render();
|
||||
this.set_title();
|
||||
this.trigger('change');
|
||||
},
|
||||
|
||||
translate_doctype_name() {
|
||||
return new Promise((resolve) => {
|
||||
const route = frappe.router.current_route = frappe.router.parse();
|
||||
const factory = route[0].toLowerCase();
|
||||
const set_name = () => {
|
||||
const d = frappe.router.doctype_names[route[1]];
|
||||
route[1] = d.doctype;
|
||||
frappe.router.doctype_layout = d.doctype_layout;
|
||||
resolve();
|
||||
};
|
||||
parse(route) {
|
||||
route = this.get_sub_path_string(route).split('/');
|
||||
route = $.map(route, this.decode_component);
|
||||
this.set_route_options_from_url(route);
|
||||
return this.convert_to_standard_route(route);
|
||||
},
|
||||
|
||||
if (frappe.router.factory_views.includes(factory)) {
|
||||
// translate the doctype to its original name
|
||||
if (frappe.router.doctype_names[route[1]]) {
|
||||
set_name();
|
||||
convert_to_standard_route(route) {
|
||||
// /app/user = ["List", "User"]
|
||||
// /app/user/view/report = ["List", "User", "Report"]
|
||||
// /app/user/view/tree = ["Tree", "User"]
|
||||
// /app/user/user-001 = ["Form", "User", "user-001"]
|
||||
// /app/user/user-001 = ["Form", "User", "user-001"]
|
||||
let standard_route = route;
|
||||
let doctype_route = this.routes[route[0]];
|
||||
|
||||
if (doctype_route) {
|
||||
// doctype route
|
||||
if (route[1]) {
|
||||
if (route[2] && route[1]==='view') {
|
||||
if (route[2].toLowerCase()==='tree') {
|
||||
standard_route = ['Tree', doctype_route.doctype];
|
||||
} else {
|
||||
standard_route = ['List', doctype_route.doctype, frappe.utils.to_title_case(route[2])];
|
||||
}
|
||||
} else {
|
||||
frappe.xcall('frappe.desk.utils.get_doctype_name', {name: route[1]}).then((data) => {
|
||||
frappe.router.doctype_names[route[1]] = data.name_map;
|
||||
set_name();
|
||||
});
|
||||
standard_route = ['Form', doctype_route.doctype, route[1]];
|
||||
}
|
||||
} else if (frappe.model.is_single(doctype_route.doctype)) {
|
||||
standard_route = ['Form', doctype_route.doctype, doctype_route.doctype];
|
||||
} else {
|
||||
resolve();
|
||||
standard_route = ['List', doctype_route.doctype, 'List'];
|
||||
}
|
||||
});
|
||||
|
||||
if (doctype_route.doctype_layout) {
|
||||
// set the layout
|
||||
this.doctype_layout = doctype_route.doctype_layout;
|
||||
}
|
||||
}
|
||||
|
||||
return standard_route;
|
||||
},
|
||||
|
||||
set_history(sub_path) {
|
||||
frappe.route_history.push(frappe.router.current_route);
|
||||
frappe.route_history.push(this.current_route);
|
||||
frappe.route_titles[sub_path] = frappe._original_title || document.title;
|
||||
frappe.ui.hide_open_dialog();
|
||||
},
|
||||
|
||||
render() {
|
||||
if (this.current_route[0]) {
|
||||
this.render_page();
|
||||
} else {
|
||||
// Show home
|
||||
frappe.views.pageview.show('');
|
||||
}
|
||||
},
|
||||
|
||||
render_page() {
|
||||
// create the page generator (factory) object and call `show`
|
||||
// if there is no generator, render the `Page` object
|
||||
|
||||
// first the router needs to know if its a "page", "doctype", "workspace"
|
||||
|
||||
const route = frappe.router.current_route;
|
||||
const route = this.current_route;
|
||||
const factory = frappe.utils.to_title_case(route[0]);
|
||||
if (factory === 'Workspace') {
|
||||
frappe.views.pageview.show('');
|
||||
|
|
@ -155,12 +195,12 @@ frappe.router = {
|
|||
re_route(sub_path) {
|
||||
if (frappe.re_route[sub_path] !== undefined) {
|
||||
// after saving a doc, for example,
|
||||
// "New DocType 1" and the renamed "TestDocType", both exist in history
|
||||
// "new-doctype-1" and the renamed "TestDocType", both exist in history
|
||||
// now if we try to go back,
|
||||
// it doesn't allow us to go back to the one prior to "New DocType 1"
|
||||
// it doesn't allow us to go back to the one prior to "new-doctype-1"
|
||||
// Hence if this check is true, instead of changing location hash,
|
||||
// we just do a back to go to the doc previous to the "New DocType 1"
|
||||
var re_route_val = frappe.router.get_sub_path(frappe.re_route[sub_path]);
|
||||
// we just do a back to go to the doc previous to the "new-doctype-1"
|
||||
var re_route_val = this.get_sub_path(frappe.re_route[sub_path]);
|
||||
if (decodeURIComponent(re_route_val) === decodeURIComponent(sub_path)) {
|
||||
window.history.back();
|
||||
return true;
|
||||
|
|
@ -185,32 +225,14 @@ frappe.router = {
|
|||
// set the route (push state) with given arguments
|
||||
// example 1: frappe.set_route('a', 'b', 'c');
|
||||
// example 2: frappe.set_route(['a', 'b', 'c']);
|
||||
// example 3: frappe.set_route('a/b/c');
|
||||
// example 3: frappe.set_route('a/b/c');
|
||||
let route = arguments;
|
||||
|
||||
return new Promise(resolve => {
|
||||
var route = arguments;
|
||||
if (route.length===1 && $.isArray(route[0])) {
|
||||
// called as frappe.set_route(['a', 'b', 'c']);
|
||||
route = route[0];
|
||||
}
|
||||
|
||||
if (route.length===1 && route[0].includes('/')) {
|
||||
// called as frappe.set_route('a/b/c')
|
||||
route = $.map(route[0].split('/'), frappe.router.decode_component);
|
||||
}
|
||||
|
||||
if (route && route[0] == '') {
|
||||
route.shift();
|
||||
}
|
||||
|
||||
if (route && ['desk', 'app'].includes(route[0])) {
|
||||
// we only need subpath, remove "app" (or "desk")
|
||||
route.shift();
|
||||
}
|
||||
|
||||
frappe.router.slug_parts(route);
|
||||
const sub_path = frappe.router.make_url_from_list(route);
|
||||
frappe.router.push_state(sub_path);
|
||||
route = this.get_route_from_arguments(route);
|
||||
route = this.convert_from_standard_route(route);
|
||||
const sub_path = this.make_url(route);
|
||||
this.push_state(sub_path);
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.after_ajax && frappe.after_ajax(() => {
|
||||
|
|
@ -220,19 +242,67 @@ frappe.router = {
|
|||
});
|
||||
},
|
||||
|
||||
slug_parts(route) {
|
||||
// slug doctype
|
||||
get_route_from_arguments(route) {
|
||||
if (route.length===1 && $.isArray(route[0])) {
|
||||
// called as frappe.set_route(['a', 'b', 'c']);
|
||||
route = route[0];
|
||||
}
|
||||
|
||||
// if app is part of the route, then first 2 elements are "" and "app"
|
||||
if (route[0] && frappe.router.factory_views.includes(route[0].toLowerCase())) {
|
||||
route[0] = route[0].toLowerCase();
|
||||
route[1] = frappe.router.slug(route[1]);
|
||||
if (route.length===1 && route[0].includes('/')) {
|
||||
// called as frappe.set_route('a/b/c')
|
||||
route = $.map(route[0].split('/'), this.decode_component);
|
||||
}
|
||||
|
||||
if (route && route[0] == '') {
|
||||
route.shift();
|
||||
}
|
||||
|
||||
if (route && ['desk', 'app'].includes(route[0])) {
|
||||
// we only need subpath, remove "app" (or "desk")
|
||||
route.shift();
|
||||
}
|
||||
|
||||
return route;
|
||||
|
||||
},
|
||||
|
||||
convert_from_standard_route(route) {
|
||||
// ["List", "Sales Order"] => /sales-order
|
||||
// ["Form", "Sales Order", "SO-0001"] => /sales-order/SO-0001
|
||||
// ["Tree", "Account"] = /account/view/tree
|
||||
|
||||
const view = route[0].toLowerCase();
|
||||
if (view === 'list') {
|
||||
if (route[2] && route[2] !== 'list') {
|
||||
const new_route = [this.slug(route[1]), 'view', route[2].toLowerCase()];
|
||||
|
||||
// calendar / inbox
|
||||
if (route[3]) new_route.push(route[3]);
|
||||
return new_route;
|
||||
} else {
|
||||
return [this.slug(route[1])]
|
||||
}
|
||||
} else if (view === 'form') {
|
||||
return [this.slug(route[1]), route[2]]
|
||||
} else if (view === 'tree') {
|
||||
return [this.slug(route[1]), 'view', 'tree'];
|
||||
}
|
||||
return route;
|
||||
},
|
||||
|
||||
make_url_from_list(params) {
|
||||
return $.map(params, function(a) {
|
||||
slug_parts(route) {
|
||||
// slug doctype
|
||||
|
||||
// if app is part of the route, then first 2 elements are "" and "app"
|
||||
if (route[0] && this.factory_views.includes(route[0].toLowerCase())) {
|
||||
route[0] = route[0].toLowerCase();
|
||||
route[1] = this.slug(route[1]);
|
||||
}
|
||||
return route;
|
||||
},
|
||||
|
||||
make_url(params) {
|
||||
return '/app/' + $.map(params, function(a) {
|
||||
if ($.isPlainObject(a)) {
|
||||
frappe.route_options = a;
|
||||
return null;
|
||||
|
|
@ -247,10 +317,8 @@ frappe.router = {
|
|||
}).join('/');
|
||||
},
|
||||
|
||||
push_state(sub_path) {
|
||||
push_state(url) {
|
||||
// change the URL and call the router
|
||||
const url = `/app/${sub_path}`;
|
||||
|
||||
if (window.location.pathname !== url) {
|
||||
// cleanup any remenants of v1 routing
|
||||
window.location.hash = '';
|
||||
|
|
@ -259,19 +327,10 @@ frappe.router = {
|
|||
history.pushState(null, null, url);
|
||||
|
||||
// now process the route
|
||||
frappe.router.route();
|
||||
this.route();
|
||||
}
|
||||
},
|
||||
|
||||
parse(route) {
|
||||
route = frappe.router.get_sub_path_string(route).split('/');
|
||||
route = $.map(route, frappe.router.decode_component);
|
||||
|
||||
frappe.router.set_route_options_from_url(route);
|
||||
|
||||
return route;
|
||||
},
|
||||
|
||||
get_sub_path_string(route) {
|
||||
// return clean sub_path from hash or url
|
||||
// supports both v1 and v2 routing
|
||||
|
|
@ -279,7 +338,7 @@ frappe.router = {
|
|||
route = window.location.hash || window.location.pathname;
|
||||
}
|
||||
|
||||
return frappe.router.strip_prefix(route);
|
||||
return this.strip_prefix(route);
|
||||
},
|
||||
|
||||
strip_prefix(route) {
|
||||
|
|
@ -292,8 +351,8 @@ frappe.router = {
|
|||
},
|
||||
|
||||
get_sub_path(route) {
|
||||
var sub_path = frappe.router.get_sub_path_string(route);
|
||||
route = $.map(sub_path.split('/'), frappe.router.decode_component).join('/');
|
||||
var sub_path = this.get_sub_path_string(route);
|
||||
route = $.map(sub_path.split('/'), this.decode_component).join('/');
|
||||
|
||||
return route;
|
||||
},
|
||||
|
|
@ -333,10 +392,9 @@ frappe.router = {
|
|||
};
|
||||
|
||||
// global functions for backward compatibility
|
||||
frappe.route = frappe.router.route;
|
||||
frappe.get_route = () => frappe.router.current_route;
|
||||
frappe.get_route_str = () => frappe.router.current_route.join('/');
|
||||
frappe.set_route = frappe.router.set_route;
|
||||
frappe.set_route = function() { return frappe.router.set_route.apply(frappe.router, arguments) };
|
||||
|
||||
frappe.get_prev_route = function() {
|
||||
if (frappe.route_history && frappe.route_history.length > 1) {
|
||||
|
|
@ -356,4 +414,4 @@ frappe.has_route_options = function() {
|
|||
return Boolean(Object.keys(frappe.route_options || {}).length);
|
||||
};
|
||||
|
||||
frappe.utils.make_event_emitter(frappe.route);
|
||||
frappe.utils.make_event_emitter(frappe.router);
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
frappe.provide('frappe.route');
|
||||
frappe.route_history_queue = [];
|
||||
const routes_to_skip = ['Form', 'social', 'setup-wizard', 'recorder'];
|
||||
|
||||
const save_routes = frappe.utils.debounce(() => {
|
||||
if (frappe.session.user === 'Guest') return;
|
||||
const routes = frappe.route_history_queue;
|
||||
frappe.route_history_queue = [];
|
||||
|
||||
frappe.xcall('frappe.deferred_insert.deferred_insert', {
|
||||
'doctype': 'Route History',
|
||||
'records': routes
|
||||
}).catch(() => {
|
||||
frappe.route_history_queue.concat(routes);
|
||||
});
|
||||
});
|
||||
|
||||
}, 10000);
|
||||
|
||||
frappe.route.on('change', () => {
|
||||
frappe.router.on('change', () => {
|
||||
const route = frappe.get_route();
|
||||
if (is_route_useful(route)) {
|
||||
frappe.route_history_queue.push({
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ frappe.ui.Notifications = class Notifications {
|
|||
}
|
||||
|
||||
make() {
|
||||
this.dropdown = $('.navbar').find('.dropdown-notifications');
|
||||
this.dropdown.removeClass("hidden")
|
||||
this.dropdown = $('.navbar').find('.dropdown-notifications').removeClass('hidden');
|
||||
this.dropdown_list = this.dropdown.find('.notifications-list');
|
||||
this.header_items = this.dropdown_list.find('.header-items');
|
||||
this.header_actions = this.dropdown_list.find('.header-actions');
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ frappe.ui.Tags = class {
|
|||
|
||||
setup(parent, placeholder) {
|
||||
this.$ul = parent;
|
||||
this.$input = $(`<input class="tags-input"></input>`);
|
||||
this.$input = $(`<input class="tags-input form-control"></input>`);
|
||||
|
||||
this.$inputWrapper = this.get_list_element(this.$input);
|
||||
this.$placeholder = this.get_list_element($(`<span class="tags-placeholder text-muted">${placeholder}</span>`));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
setup: function(element) {
|
||||
var me = this;
|
||||
|
||||
$('.search-bar').removeClass('hidden');
|
||||
var $input = $(element);
|
||||
var input = $input.get(0);
|
||||
|
||||
|
|
@ -122,6 +123,7 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
$input.blur();
|
||||
});
|
||||
frappe.search.utils.setup_recent();
|
||||
frappe.tags.utils.fetch_tags();
|
||||
},
|
||||
|
||||
add_help: function() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<ul class="nav navbar-nav d-none d-sm-flex" id="navbar-breadcrumbs"></ul>
|
||||
<div class="collapse navbar-collapse justify-content-end">
|
||||
<form class="form-inline fill-width justify-content-end" role="search" onsubmit="return false;">
|
||||
<div class="input-group search-bar text-muted">
|
||||
<div class="input-group search-bar text-muted hidden">
|
||||
<input
|
||||
id="navbar-search"
|
||||
type="text"
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ frappe.search.SearchDialog = class {
|
|||
frappe.set_route(result.route);
|
||||
// hashchange didn't fire!
|
||||
if (window.location.hash == previous_hash) {
|
||||
frappe.route();
|
||||
frappe.router.route();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,15 +14,12 @@ frappe.ui.toolbar.Toolbar = class {
|
|||
|
||||
this.setup_awesomebar();
|
||||
this.setup_notifications();
|
||||
this.setup_help();
|
||||
this.make();
|
||||
}
|
||||
|
||||
make () {
|
||||
// this.setup_sidebar();
|
||||
this.setup_help();
|
||||
|
||||
this.bind_events();
|
||||
|
||||
$(document).trigger('toolbar_setup');
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +43,12 @@ frappe.ui.toolbar.Toolbar = class {
|
|||
|
||||
|
||||
setup_help () {
|
||||
if (!frappe.boot.desk_settings.notifications) {
|
||||
// hide the help section
|
||||
$('.navbar .vertical-bar').removeClass('d-sm-block');
|
||||
$('.dropdown-help').removeClass('d-lg-block');
|
||||
return;
|
||||
}
|
||||
frappe.provide('frappe.help');
|
||||
frappe.help.show_results = show_results;
|
||||
|
||||
|
|
|
|||
|
|
@ -816,7 +816,7 @@ Object.assign(frappe.utils, {
|
|||
display_text = display_text || name;
|
||||
doctype = encodeURIComponent(doctype);
|
||||
name = encodeURIComponent(name);
|
||||
const route = ['/app/Form', doctype, name].join('/');
|
||||
const route = `/app/${frappe.router.slug(doctype)}/${name}`;
|
||||
if (html) {
|
||||
return `<a href="${route}">${display_text}</a>`;
|
||||
}
|
||||
|
|
@ -1127,7 +1127,7 @@ Object.assign(frappe.utils, {
|
|||
let doctype_slug = frappe.router.slug(item.doctype);
|
||||
|
||||
if (frappe.model.is_single(item.doctype)) {
|
||||
route = "form/" + doctype_slug;
|
||||
route = doctype_slug;
|
||||
} else {
|
||||
if (!item.doc_view) {
|
||||
if (frappe.model.is_tree(item.doctype)) {
|
||||
|
|
@ -1142,22 +1142,22 @@ Object.assign(frappe.utils, {
|
|||
if (item.filters) {
|
||||
frappe.route_options = item.filters;
|
||||
}
|
||||
route = "list/" + doctype_slug;
|
||||
route = doctype_slug;
|
||||
break;
|
||||
case "Tree":
|
||||
route = "tree/" + doctype_slug;
|
||||
route = `${doctype_slug}/view/tree`;
|
||||
break;
|
||||
case "Report Builder":
|
||||
route = "list/" + doctype_slug + "/Report";
|
||||
route = `${doctype_slug}/view/report`;
|
||||
break;
|
||||
case "Dashboard":
|
||||
route = "list/" + doctype_slug + "/Dashboard";
|
||||
route = `${doctype_slug}/view/dashboard`;
|
||||
break;
|
||||
case "New":
|
||||
route = "form/" + doctype_slug + "/New " + item.doctype;
|
||||
route = `${doctype_slug}/new`;
|
||||
break;
|
||||
case "Calendar":
|
||||
route = "list/" + doctype_slug + "/Calendar/Default";
|
||||
route = `${doctype_slug}/view/calendar/Default`;
|
||||
break;
|
||||
default:
|
||||
frappe.throw({ message: __("Not a valid DocType view:") + item.doc_view, title: __("Unknown View") });
|
||||
|
|
@ -1167,7 +1167,7 @@ Object.assign(frappe.utils, {
|
|||
} else if (type === "report" && item.is_query_report) {
|
||||
route = "query-report/" + item.name;
|
||||
} else if (type === "report") {
|
||||
route = "List/" + frappe.router.slug(item.doctype) + "/Report/" + item.name;
|
||||
route = frappe.router.slug(item.doctype) + "/view/report/" + item.name;
|
||||
} else if (type === "page") {
|
||||
route = item.name;
|
||||
} else if (type === "dashboard") {
|
||||
|
|
|
|||
|
|
@ -114,11 +114,12 @@ frappe.breadcrumbs = {
|
|||
// no user listview for non-system managers and single doctypes
|
||||
} else {
|
||||
let route;
|
||||
const doctype_route = frappe.router.slug(frappe.router.doctype_layout || breadcrumbs.doctype);
|
||||
if (frappe.boot.treeviews.indexOf(breadcrumbs.doctype) !== -1) {
|
||||
let view = frappe.model.user_settings[breadcrumbs.doctype].last_view || 'Tree';
|
||||
route = view + '/' + breadcrumbs.doctype;
|
||||
route = `${doctype_route}/view/${view}`;
|
||||
} else {
|
||||
route = 'list/' + (frappe.router.doctype_layout || breadcrumbs.doctype);
|
||||
route = doctype_route;
|
||||
}
|
||||
$(`<li><a href="/app/${route}">${doctype}</a></li>`)
|
||||
.appendTo($breadcrumbs)
|
||||
|
|
@ -132,7 +133,7 @@ frappe.breadcrumbs = {
|
|||
if (breadcrumbs.doctype && frappe.get_route()[0] === "print") {
|
||||
set_list_breadcrumb(breadcrumbs.doctype);
|
||||
let docname = frappe.get_route()[2];
|
||||
let form_route = `/app/form/${frappe.router.slug(breadcrumbs.doctype)}/${docname}`;
|
||||
let form_route = `/app/${frappe.router.slug(breadcrumbs.doctype)}/${docname}`;
|
||||
$(`<li><a href="${form_route}">${docname}</a></li>`)
|
||||
.appendTo($breadcrumbs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
|
|||
frappe.model.with_doctype(doctype, () => {
|
||||
this.page = frappe.container.add_page("form/" + doctype_layout);
|
||||
frappe.views.formview[doctype_layout] = this.page;
|
||||
this.page.frm = new frappe.ui.form.Form(doctype, this.page, true, frappe.router.doctype_layout);
|
||||
this.show_doc(route);
|
||||
this.make_and_show(doctype, route);
|
||||
});
|
||||
} else {
|
||||
this.show_doc(route);
|
||||
|
|
@ -22,6 +21,22 @@ frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
|
|||
this.setup_events();
|
||||
}
|
||||
|
||||
make_and_show(doctype, route) {
|
||||
if (frappe.router.doctype_layout) {
|
||||
frappe.model.with_doc('DocType Layout', frappe.router.doctype_layout, () => {
|
||||
this.make_form(doctype);
|
||||
this.show_doc(route);
|
||||
})
|
||||
} else {
|
||||
this.make_form(doctype);
|
||||
this.show_doc(route);
|
||||
}
|
||||
}
|
||||
|
||||
make_form(doctype) {
|
||||
this.page.frm = new frappe.ui.form.Form(doctype, this.page, true, frappe.router.doctype_layout);
|
||||
}
|
||||
|
||||
setup_events() {
|
||||
if (!this.initialized) {
|
||||
$(document).on("page-change", function() {
|
||||
|
|
@ -54,7 +69,7 @@ frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
|
|||
}
|
||||
|
||||
const doc = frappe.get_doc(doctype, name);
|
||||
if (doc && (doc.__islocal || frappe.model.is_fresh(doc))) {
|
||||
if (doc && frappe.model.get_docinfo(doctype, name) && (doc.__islocal || frappe.model.is_fresh(doc))) {
|
||||
// is document available and recent?
|
||||
this.render(doctype_layout, name);
|
||||
} else {
|
||||
|
|
@ -67,7 +82,7 @@ frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
|
|||
if (r && r['403']) return; // not permitted
|
||||
|
||||
if (!(locals[doctype] && locals[doctype][name])) {
|
||||
if (name && name==='new') {
|
||||
if (name && name.substr(0,3)==='new') {
|
||||
this.render_new_doc(doctype, name, doctype_layout);
|
||||
} else {
|
||||
frappe.show_not_found(route);
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ frappe.views.KanbanView.get_kanbans = function (doctype) {
|
|||
.then((kanban_boards) => {
|
||||
if (kanban_boards) {
|
||||
kanban_boards.forEach(board => {
|
||||
let route = ['List', board.reference_doctype, 'Kanban', board.name].join('/');
|
||||
let route = `/app/${frappe.router.slug(board.reference_doctype)}/kanban/${board.name}`;
|
||||
kanbans.push({ name: board.name, route: route });
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,16 +44,6 @@ details > summary:focus {
|
|||
color: @border-color !important;
|
||||
}
|
||||
|
||||
// transition
|
||||
a,
|
||||
.badge {
|
||||
.transition(.2s);
|
||||
}
|
||||
|
||||
.btn {
|
||||
.transition(background-color .2s);
|
||||
}
|
||||
|
||||
a.disabled,
|
||||
a.disabled:hover {
|
||||
color: #888;
|
||||
|
|
|
|||
|
|
@ -123,24 +123,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.progress-area {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
|
||||
.progress-chart {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.progress-message {
|
||||
font-feature-settings: "tnum" 1;
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin: 0px;
|
||||
// padding: 15px;
|
||||
|
|
@ -173,21 +155,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.hide-border {
|
||||
border-top: none !important;
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.empty-section {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.modal {
|
||||
.hide-border {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.help ol {
|
||||
padding-left: 19px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@
|
|||
font-size: var(--text-md);
|
||||
}
|
||||
|
||||
.form-section {
|
||||
.form-section, .form-dashboard-section {
|
||||
margin: 0px;
|
||||
|
||||
.form-section-description {
|
||||
margin-bottom: 10px;
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.section-head {
|
||||
|
|
@ -59,14 +61,11 @@
|
|||
.section-body:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.section-head {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.form-dashboard-section {
|
||||
padding-left: calc(var(--padding-lg) + var(--padding-xs));
|
||||
padding-right: calc(var(--padding-lg) + var(--padding-xs));
|
||||
padding-bottom: var(--padding-lg);
|
||||
.form-dashboard-section .section-body {
|
||||
display: block;
|
||||
padding-left: var(--padding-md);
|
||||
padding-right: var(--padding-md);
|
||||
padding-bottom: var(--padding-md);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -272,3 +271,21 @@
|
|||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-area {
|
||||
padding-top: var(--padding-md);
|
||||
padding-bottom: var(--padding-md);
|
||||
|
||||
.progress-chart {
|
||||
padding-top: var(--padding-lg);
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-bottom: var(--margin-xs);
|
||||
}
|
||||
|
||||
.progress-message {
|
||||
font-feature-settings: "tnum" 1;
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,21 @@ html {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
// transition
|
||||
* {
|
||||
transition: background-color 0.5s, background 0.5s;
|
||||
}
|
||||
|
||||
a,
|
||||
.badge {
|
||||
transition: 0.2s,
|
||||
}
|
||||
|
||||
.btn {
|
||||
transition: background-color 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
|
@ -264,26 +279,25 @@ select.input-xs {
|
|||
|
||||
/* dropdowns */
|
||||
|
||||
.dropdown-backdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
min-width: 200px;
|
||||
padding: 4px;
|
||||
font-size: var(--text-md);
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
color: $text-color;
|
||||
border-radius: 6px;
|
||||
|
||||
.dropdown-divider {
|
||||
margin: 4px 0;
|
||||
}
|
||||
a:not([href]):hover:active {
|
||||
color: $component-active-color ;
|
||||
}
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu .divider {
|
||||
|
|
@ -428,10 +442,10 @@ kbd {
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
margin-top: var(--margin-xs);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
// .dropdown-menu {
|
||||
// margin-top: var(--margin-xs);
|
||||
// box-shadow: var(--shadow-sm);
|
||||
// }
|
||||
|
||||
.btn-link {
|
||||
box-shadow: none !important;
|
||||
|
|
|
|||
|
|
@ -382,6 +382,13 @@ body[data-route^="Module"] .main-menu {
|
|||
max-width: 100%;
|
||||
}
|
||||
|
||||
.attachment-row, .form-tag-row {
|
||||
.data-pill {
|
||||
background-color: var(--bg-gray);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.form-tag-row {
|
||||
margin-right: var(--margin-xs);
|
||||
display: inline-flex;
|
||||
|
|
@ -492,7 +499,7 @@ button.data-pill {
|
|||
|
||||
.tags-input {
|
||||
margin-bottom: var(--margin-sm);
|
||||
font-size: var(--text-md);
|
||||
font-size: var(--text-xs);
|
||||
background: inherit;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@ html, body {
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
* {
|
||||
transition: background-color 0.5s, background 0.5s;
|
||||
}
|
||||
|
||||
// colors
|
||||
$gray-900: #192734;
|
||||
$gray-800: #313B44;
|
||||
|
|
@ -34,6 +30,8 @@ $border-radius: var(--border-radius);
|
|||
$border-radius-sm: var(--border-radius-sm);
|
||||
$border-radius-lg: var(--border-radius-lg);
|
||||
|
||||
$nav-divider-margin-y: 4px;
|
||||
|
||||
$container-max-widths: (
|
||||
sm: 540px,
|
||||
md: 840px,
|
||||
|
|
@ -69,6 +67,7 @@ $input-focus-border-color: var(--gray-500);
|
|||
$input-border-radius: var(--border-radius);
|
||||
|
||||
// dropdown
|
||||
$dropdown-color: var(--text-color);
|
||||
$dropdown-bg: var(--fg-color);
|
||||
$dropdown-border-color: var(--dark-border-color);
|
||||
$dropdown-link-color: var(--text-color);
|
||||
|
|
@ -77,6 +76,7 @@ $dropdown-link-hover-bg: var(--fg-hover-color);
|
|||
$dropdown-link-disabled-color: var(--gray-600);
|
||||
$dropdown-header-color: var(--gray-600);
|
||||
$dropdown-divider-bg: var(--border-color);
|
||||
$dropdown-min-width: 200px;
|
||||
|
||||
// button
|
||||
$btn-padding-y-lg: 1rem !default;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from six.moves.urllib.parse import unquote
|
|||
from six import text_type
|
||||
from frappe.cache_manager import clear_user_cache
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def clear(user=None):
|
||||
frappe.local.session_obj.update(force=True)
|
||||
frappe.local.db.commit()
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@
|
|||
"is_published_field": "published",
|
||||
"links": [],
|
||||
"max_attachments": 5,
|
||||
"modified": "2020-08-31 21:01:51.100349",
|
||||
"modified": "2020-12-07 23:27:23.644512",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Blog Post",
|
||||
|
|
@ -229,7 +229,7 @@
|
|||
"write": 1
|
||||
}
|
||||
],
|
||||
"route": "/blog",
|
||||
"route": "blog-post",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"title_field": "title",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from frappe.website.utils import (find_first_image, get_html_content_based_on_ty
|
|||
|
||||
class BlogPost(WebsiteGenerator):
|
||||
website = frappe._dict(
|
||||
route = 'blog',
|
||||
order_by = "published_on desc"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ from frappe import _
|
|||
import frappe.sessions
|
||||
|
||||
def get_context(context):
|
||||
if frappe.session.user == "Guest":
|
||||
frappe.throw(_("Log in to access this page."), frappe.PermissionError)
|
||||
# if frappe.session.user == "Guest":
|
||||
# frappe.throw(_("Log in to access this page."), frappe.PermissionError)
|
||||
# elif frappe.db.get_value("User", frappe.session.user, "user_type") == "Website User":
|
||||
# frappe.throw(_("You are not permitted to access this page."), frappe.PermissionError)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ def get_context(context):
|
|||
redirect_to = get_home_page()
|
||||
else:
|
||||
redirect_to = "/app"
|
||||
frappe.local.flags.redirect_location = redirect_to
|
||||
raise frappe.Redirect
|
||||
|
||||
if redirect_to != 'login':
|
||||
frappe.local.flags.redirect_location = redirect_to
|
||||
raise frappe.Redirect
|
||||
|
||||
# get settings from site config
|
||||
context.no_header = True
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue