[feature] Global Search (again) (#2710)
* [start] global search frappe/erpnext#6674 * [fix] setup before running test * [start] global search frappe/erpnext#6674 * Display result as rudimentary list, rebuild old doctypes * Media view, child tables, delete document updates, searchable fields * More results UI * Code clean up * remove msgprint from document.py to resolve merge conflict * Modularization stage 1, get show more to work with it * Dedicated modal Search bar works, some clean up needed * Can't data-dismiss on links, Bootstrap issue, use hashchange * Accomodate missing field content syndrome * Search in boolean mode, make GS default in awesome bar, fix double modal bug and cleanup * Add in Meta * Add in customize form * Modularise Global Search * Search object * Commonify Search UI: Stage I * II: save list state, UI, default condensed view, refactor * Fix SQL bug, Refactor awesome bar, Fix unicode bug, add nav results * Refactor using separate search objects, some async issues * Fix async flow * Fix preceding more list bug * UI additions * another async fix, back link * Help: Stage I * Help: Stage II * Background jobs, fix route options bug * Fix GS syncing on install * Add GS options in awesome bar: test * Input now remembers search type state * More UI updates * Add description for GS results in awesome bar * Fix help modal bug * Fix: not commit during install * Test cases, some fixes * Update in_test flag in enqueue * Disable GS sync when not install_db * Add flag check * Disable field in child tables * Cleanups * Create table fix * Fix redis exception, remove commit enqueue, add gs in migrate * Fix tests * Single enqueue * cleanups * Fix tests * Fix event test * Fix duplication, search as first option * Add show name in global search * fix event tests and desk.less * Fix communication.json * [fixes] wip * [fix] tests * [minor] for tests * [minor] for tests * [minor] for tests * [minor] for tests
This commit is contained in:
parent
1f58e36d37
commit
86ceb21005
38 changed files with 4350 additions and 2702 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -24,6 +24,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
|
|
@ -52,6 +53,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Module",
|
||||
|
|
@ -83,6 +85,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Is Child Table",
|
||||
|
|
@ -114,6 +117,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Is Single",
|
||||
|
|
@ -145,6 +149,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Editable Grid",
|
||||
|
|
@ -175,6 +180,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Quick Entry",
|
||||
|
|
@ -205,6 +211,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Track Changes",
|
||||
|
|
@ -233,6 +240,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -260,6 +268,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Show in Module Section",
|
||||
|
|
@ -290,6 +299,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Icon",
|
||||
|
|
@ -317,6 +327,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Custom?",
|
||||
|
|
@ -344,6 +355,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Beta",
|
||||
|
|
@ -374,6 +386,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Image View",
|
||||
|
|
@ -402,6 +415,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Plugin",
|
||||
|
|
@ -429,6 +443,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Fields",
|
||||
|
|
@ -457,6 +472,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Fields",
|
||||
|
|
@ -487,6 +503,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Naming",
|
||||
|
|
@ -515,6 +532,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Auto Name",
|
||||
|
|
@ -544,6 +562,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Name Case",
|
||||
|
|
@ -574,6 +593,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
|
|
@ -604,6 +624,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -632,6 +653,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Title Field",
|
||||
|
|
@ -660,6 +682,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Search Fields",
|
||||
|
|
@ -690,6 +713,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Image Field",
|
||||
|
|
@ -721,6 +745,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Sort Field",
|
||||
|
|
@ -750,6 +775,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Sort Order",
|
||||
|
|
@ -780,6 +806,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Timeline Field",
|
||||
|
|
@ -809,6 +836,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Permission Rules",
|
||||
|
|
@ -837,6 +865,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Permissions",
|
||||
|
|
@ -868,6 +897,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -894,6 +924,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Permissions Settings",
|
||||
|
|
@ -921,6 +952,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "User Cannot Create",
|
||||
|
|
@ -950,6 +982,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "User Cannot Search",
|
||||
|
|
@ -979,6 +1012,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Submittable",
|
||||
|
|
@ -1007,6 +1041,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Import",
|
||||
|
|
@ -1034,6 +1069,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Rename",
|
||||
|
|
@ -1063,6 +1099,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "In Dialog",
|
||||
|
|
@ -1092,6 +1129,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Show Print First",
|
||||
|
|
@ -1110,6 +1148,35 @@
|
|||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "show_name_in_global_search",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Make \"name\" searchable in Global Search",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
|
|
@ -1121,6 +1188,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Max Attachments",
|
||||
|
|
@ -1150,6 +1218,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Other Settings",
|
||||
|
|
@ -1177,6 +1246,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hide Heading",
|
||||
|
|
@ -1206,6 +1276,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hide Toolbar",
|
||||
|
|
@ -1235,6 +1306,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hide Copy",
|
||||
|
|
@ -1264,6 +1336,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Track Seen",
|
||||
|
|
@ -1292,6 +1365,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Print Format",
|
||||
|
|
@ -1319,6 +1393,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Advanced",
|
||||
|
|
@ -1349,6 +1424,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Database Engine",
|
||||
|
|
@ -1379,7 +1455,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-12-29 14:39:46.191331",
|
||||
"modified": "2017-02-13 12:09:33.488890",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocType",
|
||||
|
|
@ -1395,7 +1471,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -1416,7 +1491,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -1432,6 +1506,7 @@
|
|||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "module",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class DocType(Document):
|
|||
- Validate series
|
||||
- Check fieldnames (duplication etc)
|
||||
- Clear permission table for child tables
|
||||
- Add `amended_from` and `ameneded_by` if Amendable"""
|
||||
- Add `amended_from` and `amended_by` if Amendable"""
|
||||
self.check_developer_mode()
|
||||
|
||||
self.validate_name()
|
||||
|
|
@ -59,6 +59,12 @@ class DocType(Document):
|
|||
|
||||
self.make_amendable()
|
||||
self.validate_website()
|
||||
|
||||
try:
|
||||
self.before_update = frappe.get_doc('DocType', self.name)
|
||||
except frappe.DoesNotExistError:
|
||||
pass
|
||||
|
||||
if not self.is_new():
|
||||
self.setup_fields_to_fetch()
|
||||
|
||||
|
|
@ -162,6 +168,7 @@ class DocType(Document):
|
|||
self.autoname = "naming_series:"
|
||||
|
||||
# validate field name if autoname field:fieldname is used
|
||||
|
||||
if autoname and autoname.startswith('field:'):
|
||||
field = autoname.split(":")[1]
|
||||
if not field or field not in [ df.fieldname for df in self.fields ]:
|
||||
|
|
@ -201,13 +208,31 @@ class DocType(Document):
|
|||
delete_notification_count_for(doctype=self.name)
|
||||
frappe.clear_cache(doctype=self.name)
|
||||
|
||||
if not frappe.flags.in_install and hasattr(self, 'before_update'):
|
||||
self.sync_global_search()
|
||||
|
||||
def sync_global_search(self):
|
||||
'''If global search settings are changed, rebuild search properties for this table'''
|
||||
global_search_fields_before_update = [d.fieldname for d in
|
||||
self.before_update.fields if d.in_global_search]
|
||||
if self.before_update.show_name_in_global_search:
|
||||
global_search_fields_before_update.append('name')
|
||||
|
||||
global_search_fields_after_update = [d.fieldname for d in
|
||||
self.fields if d.in_global_search]
|
||||
if self.show_name_in_global_search:
|
||||
global_search_fields_after_update.append('name')
|
||||
|
||||
if set(global_search_fields_before_update) != set(global_search_fields_after_update):
|
||||
frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype',
|
||||
now=frappe.flags.in_test, doctype=self.name)
|
||||
|
||||
def run_module_method(self, method):
|
||||
from frappe.modules import load_doctype_module
|
||||
module = load_doctype_module(self.name, self.module)
|
||||
if hasattr(module, method):
|
||||
getattr(module, method)()
|
||||
|
||||
|
||||
def before_rename(self, old, new, merge=False):
|
||||
"""Throw exception if merge. DocTypes cannot be merged."""
|
||||
if not self.custom and frappe.session.user != "Administrator":
|
||||
|
|
@ -263,7 +288,7 @@ class DocType(Document):
|
|||
import_from_files(record_list=[[self.module, 'doctype', self.name]])
|
||||
|
||||
def make_controller_template(self):
|
||||
"""Make boilderplate controller template."""
|
||||
"""Make boilerplate controller template."""
|
||||
make_boilerplate("controller.py", self)
|
||||
|
||||
if not (self.istable or self.issingle):
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ docfield_properties = {
|
|||
'ignore_user_permissions': 'Check',
|
||||
'in_list_view': 'Check',
|
||||
'in_standard_filter': 'Check',
|
||||
'in_global_search': 'Check',
|
||||
'hidden': 'Check',
|
||||
'collapsible': 'Check',
|
||||
'collapsible_depends_on': 'Data',
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ class TestCustomizeForm(unittest.TestCase):
|
|||
d = self.get_customize_form("User")
|
||||
self.assertEquals(d.doc_type, "User")
|
||||
|
||||
self.assertEquals(len(d.get("fields")), len(frappe.get_doc("DocType", d.doc_type).fields) + 1)
|
||||
self.assertEquals(len(d.get("fields")),
|
||||
len(frappe.get_doc("DocType", d.doc_type).fields) + 1)
|
||||
self.assertEquals(d.get("fields")[-1].fieldname, "test_custom_field")
|
||||
self.assertEquals(d.get("fields", {"fieldname": "location"})[0].in_list_view, 1)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Label and Type",
|
||||
|
|
@ -50,6 +51,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Label",
|
||||
|
|
@ -80,6 +82,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Type",
|
||||
|
|
@ -110,6 +113,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Name",
|
||||
|
|
@ -139,7 +143,8 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Mandatory",
|
||||
"length": 0,
|
||||
|
|
@ -170,6 +175,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Unique",
|
||||
|
|
@ -198,6 +204,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "In List View",
|
||||
|
|
@ -225,6 +232,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "In Standard Filter",
|
||||
|
|
@ -242,6 +250,36 @@
|
|||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\"].indexOf(doc.fieldtype) !== -1)",
|
||||
"fieldname": "in_global_search",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "In Global Search",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
|
|
@ -253,6 +291,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -282,6 +321,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Precision",
|
||||
|
|
@ -312,6 +352,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Length",
|
||||
|
|
@ -341,6 +382,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Options",
|
||||
|
|
@ -370,6 +412,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Permissions",
|
||||
|
|
@ -399,6 +442,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Depends On",
|
||||
|
|
@ -429,6 +473,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Perm Level",
|
||||
|
|
@ -458,6 +503,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hidden",
|
||||
|
|
@ -489,6 +535,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Read Only",
|
||||
|
|
@ -518,6 +565,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Collapsible",
|
||||
|
|
@ -547,6 +595,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Collapsible Depends On",
|
||||
|
|
@ -575,6 +624,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -602,6 +652,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Ignore User Permissions",
|
||||
|
|
@ -629,6 +680,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow on Submit",
|
||||
|
|
@ -658,6 +710,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Report Hide",
|
||||
|
|
@ -688,6 +741,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Remember Last Selected Value",
|
||||
|
|
@ -716,6 +770,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Display",
|
||||
|
|
@ -744,6 +799,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default",
|
||||
|
|
@ -762,6 +818,38 @@
|
|||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "in_filter",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "In Filter",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "in_filter",
|
||||
"oldfieldtype": "Check",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "50px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "50px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
|
|
@ -773,6 +861,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -800,6 +889,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
|
|
@ -831,6 +921,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Print Hide",
|
||||
|
|
@ -861,6 +952,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Print Hide If No Value",
|
||||
|
|
@ -890,6 +982,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Print Width",
|
||||
|
|
@ -921,6 +1014,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Columns",
|
||||
|
|
@ -949,6 +1043,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Width",
|
||||
|
|
@ -980,6 +1075,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Custom Field",
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ class PropertySetter(Document):
|
|||
from frappe.core.doctype.doctype.doctype import validate_fields_for_doctype
|
||||
validate_fields_for_doctype(self.doc_type)
|
||||
|
||||
def make_property_setter(doctype, fieldname, property, value, property_type, for_doctype = False, validate_fields_for_doctype=True):
|
||||
def make_property_setter(doctype, fieldname, property, value, property_type, for_doctype = False,
|
||||
validate_fields_for_doctype=True):
|
||||
# WARNING: Ignores Permissions
|
||||
property_setter = frappe.get_doc({
|
||||
"doctype":"Property Setter",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ CREATE TABLE `tabDocField` (
|
|||
`report_hide` int(1) NOT NULL DEFAULT 0,
|
||||
`reqd` int(1) NOT NULL DEFAULT 0,
|
||||
`bold` int(1) NOT NULL DEFAULT 0,
|
||||
`in_global_search` int(1) NOT NULL DEFAULT 0,
|
||||
`collapsible` int(1) NOT NULL DEFAULT 0,
|
||||
`unique` int(1) NOT NULL DEFAULT 0,
|
||||
`no_copy` int(1) NOT NULL DEFAULT 0,
|
||||
|
|
@ -149,6 +150,7 @@ CREATE TABLE `tabDocType` (
|
|||
`engine` varchar(20) DEFAULT 'InnoDB',
|
||||
`default_print_format` varchar(255) DEFAULT NULL,
|
||||
`is_submittable` int(1) NOT NULL DEFAULT 0,
|
||||
`show_name_in_global_search` int(1) NOT NULL DEFAULT 0,
|
||||
`_user_tags` varchar(255) DEFAULT NULL,
|
||||
`custom` int(1) NOT NULL DEFAULT 0,
|
||||
`beta` int(1) NOT NULL DEFAULT 0,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ import re
|
|||
import frappe.model.meta
|
||||
from frappe.utils import now, get_datetime, cstr
|
||||
from frappe import _
|
||||
from types import StringType, UnicodeType
|
||||
from types import StringType, UnicodeType
|
||||
from frappe.utils.global_search import sync_global_search
|
||||
|
||||
class Database:
|
||||
"""
|
||||
|
|
@ -722,6 +723,8 @@ class Database:
|
|||
self.sql("commit")
|
||||
frappe.local.rollback_observers = []
|
||||
self.flush_realtime_log()
|
||||
if frappe.flags.update_global_search:
|
||||
sync_global_search()
|
||||
|
||||
def flush_realtime_log(self):
|
||||
for args in frappe.local.realtime_log:
|
||||
|
|
@ -729,7 +732,6 @@ class Database:
|
|||
|
||||
frappe.local.realtime_log = []
|
||||
|
||||
|
||||
def rollback(self):
|
||||
"""`ROLLBACK` current transaction."""
|
||||
self.sql("rollback")
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
|
|
@ -51,6 +52,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Subject",
|
||||
|
|
@ -78,6 +80,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Event Type",
|
||||
|
|
@ -109,6 +112,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Send an email reminder in the morning",
|
||||
|
|
@ -136,6 +140,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -162,6 +167,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Starts on",
|
||||
|
|
@ -189,6 +195,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Ends on",
|
||||
|
|
@ -216,6 +223,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "All Day",
|
||||
|
|
@ -243,6 +251,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -269,6 +278,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Repeat this Event",
|
||||
|
|
@ -297,6 +307,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -324,6 +335,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Repeat On",
|
||||
|
|
@ -354,6 +366,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Repeat Till",
|
||||
|
|
@ -381,6 +394,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -408,6 +422,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Monday",
|
||||
|
|
@ -436,6 +451,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Tuesday",
|
||||
|
|
@ -464,6 +480,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Wednesday",
|
||||
|
|
@ -492,6 +509,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Thursday",
|
||||
|
|
@ -520,6 +538,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Friday",
|
||||
|
|
@ -548,6 +567,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Saturday",
|
||||
|
|
@ -576,6 +596,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Sunday",
|
||||
|
|
@ -603,6 +624,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -629,6 +651,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
|
|
@ -660,6 +683,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Participants",
|
||||
|
|
@ -688,6 +712,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Groups",
|
||||
|
|
@ -718,6 +743,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Roles",
|
||||
|
|
@ -748,6 +774,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Ref Type",
|
||||
|
|
@ -778,6 +805,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Ref Name",
|
||||
|
|
@ -809,7 +837,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-12-29 14:40:19.097127",
|
||||
"modified": "2017-02-09 03:32:53.484696",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Desk",
|
||||
"name": "Event",
|
||||
|
|
@ -825,7 +853,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -846,7 +873,6 @@
|
|||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 1,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -861,6 +887,7 @@
|
|||
"quick_entry": 0,
|
||||
"read_only": 1,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_order": "DESC",
|
||||
"title_field": "subject",
|
||||
"track_changes": 1,
|
||||
|
|
|
|||
|
|
@ -10,36 +10,43 @@ import unittest
|
|||
import json
|
||||
|
||||
from frappe.desk.doctype.event.event import get_events
|
||||
from frappe.test_runner import make_test_objects
|
||||
|
||||
test_records = frappe.get_test_records('Event')
|
||||
test_user = "test1@example.com"
|
||||
|
||||
|
||||
class TestEvent(unittest.TestCase):
|
||||
def setUp(self):
|
||||
frappe.db.sql('delete from tabEvent')
|
||||
frappe.db.sql('delete from `tabEvent Role`')
|
||||
make_test_objects('Event', reset=True)
|
||||
|
||||
self.test_records = frappe.get_test_records('Event')
|
||||
self.test_user = "test1@example.com"
|
||||
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_allowed_public(self):
|
||||
frappe.set_user(test_user)
|
||||
frappe.set_user(self.test_user)
|
||||
doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 1"}))
|
||||
self.assertTrue(frappe.has_permission("Event", doc=doc))
|
||||
|
||||
def test_not_allowed_private(self):
|
||||
frappe.set_user(test_user)
|
||||
frappe.set_user(self.test_user)
|
||||
doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 2"}))
|
||||
self.assertFalse(frappe.has_permission("Event", doc=doc))
|
||||
|
||||
def test_allowed_private_if_in_event_user(self):
|
||||
name = frappe.db.get_value("Event", {"subject":"_Test Event 3"})
|
||||
frappe.share.add("Event", name, test_user, "read")
|
||||
frappe.set_user(test_user)
|
||||
frappe.share.add("Event", name, self.test_user, "read")
|
||||
frappe.set_user(self.test_user)
|
||||
doc = frappe.get_doc("Event", name)
|
||||
self.assertTrue(frappe.has_permission("Event", doc=doc))
|
||||
frappe.set_user("Administrator")
|
||||
frappe.share.remove("Event", name, test_user)
|
||||
frappe.share.remove("Event", name, self.test_user)
|
||||
|
||||
def test_event_list(self):
|
||||
frappe.set_user(test_user)
|
||||
frappe.set_user(self.test_user)
|
||||
res = frappe.get_list("Event", filters=[["Event", "subject", "like", "_Test Event%"]], fields=["name", "subject"])
|
||||
self.assertEquals(len(res), 1)
|
||||
subjects = [r.subject for r in res]
|
||||
|
|
@ -48,13 +55,13 @@ class TestEvent(unittest.TestCase):
|
|||
self.assertFalse("_Test Event 2" in subjects)
|
||||
|
||||
def test_revert_logic(self):
|
||||
ev = frappe.get_doc(test_records[0]).insert()
|
||||
ev = frappe.get_doc(self.test_records[0]).insert()
|
||||
name = ev.name
|
||||
|
||||
frappe.delete_doc("Event", ev.name)
|
||||
|
||||
# insert again
|
||||
ev = frappe.get_doc(test_records[0]).insert()
|
||||
ev = frappe.get_doc(self.test_records[0]).insert()
|
||||
|
||||
# the name should be same!
|
||||
self.assertEquals(ev.name, name)
|
||||
|
|
@ -62,7 +69,7 @@ class TestEvent(unittest.TestCase):
|
|||
def test_assign(self):
|
||||
from frappe.desk.form.assign_to import add
|
||||
|
||||
ev = frappe.get_doc(test_records[0]).insert()
|
||||
ev = frappe.get_doc(self.test_records[0]).insert()
|
||||
|
||||
add({
|
||||
"assign_to": "test@example.com",
|
||||
|
|
@ -77,7 +84,7 @@ class TestEvent(unittest.TestCase):
|
|||
|
||||
# add another one
|
||||
add({
|
||||
"assign_to": test_user,
|
||||
"assign_to": self.test_user,
|
||||
"doctype": "Event",
|
||||
"name": ev.name,
|
||||
"description": "Test Assignment"
|
||||
|
|
@ -85,11 +92,11 @@ class TestEvent(unittest.TestCase):
|
|||
|
||||
ev = frappe.get_doc("Event", ev.name)
|
||||
|
||||
self.assertEquals(set(json.loads(ev._assign)), set(["test@example.com", test_user]))
|
||||
self.assertEquals(set(json.loads(ev._assign)), set(["test@example.com", self.test_user]))
|
||||
|
||||
# close an assignment
|
||||
todo = frappe.get_doc("ToDo", {"reference_type": ev.doctype, "reference_name": ev.name,
|
||||
"owner": test_user})
|
||||
"owner": self.test_user})
|
||||
todo.status = "Closed"
|
||||
todo.save()
|
||||
|
||||
|
|
@ -120,5 +127,4 @@ class TestEvent(unittest.TestCase):
|
|||
self.assertFalse(filter(lambda e: e.name==ev.name, ev_list2))
|
||||
|
||||
ev_list3 = get_events("2015-02-01", "2015-02-01", "Administrator", for_reminder=True)
|
||||
self.assertTrue(filter(lambda e: e.name==ev.name, ev_list3))
|
||||
|
||||
self.assertTrue(filter(lambda e: e.name==ev.name, ev_list3))
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
{
|
||||
"doctype": "Event",
|
||||
"starts_on": "2014-01-01",
|
||||
"subject":"_Test Event 3",
|
||||
"subject": "_Test Event 3",
|
||||
"event_type": "Private",
|
||||
"roles": [
|
||||
{"role": "System Manager"}
|
||||
|
|
|
|||
|
|
@ -8,19 +8,23 @@
|
|||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 1,
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "role",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Role",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
|
|
@ -32,6 +36,7 @@
|
|||
"print_hide_if_no_value": 0,
|
||||
"print_width": "240px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
|
|
@ -50,7 +55,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-07-11 03:28:00.333899",
|
||||
"modified": "2017-01-30 06:39:06.384904",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Desk",
|
||||
"name": "Event Role",
|
||||
|
|
@ -59,5 +64,6 @@
|
|||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
|
|
@ -50,6 +51,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "First Name",
|
||||
|
|
@ -79,6 +81,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Last Name",
|
||||
|
|
@ -108,6 +111,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Email Address",
|
||||
|
|
@ -138,6 +142,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "User Id",
|
||||
|
|
@ -167,6 +172,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -194,6 +200,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
|
|
@ -222,6 +229,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Phone",
|
||||
|
|
@ -251,6 +259,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Mobile No",
|
||||
|
|
@ -280,6 +289,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Image",
|
||||
|
|
@ -308,6 +318,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reference",
|
||||
|
|
@ -338,6 +349,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Primary Contact",
|
||||
|
|
@ -367,6 +379,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Links",
|
||||
|
|
@ -396,6 +409,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "More Information",
|
||||
|
|
@ -425,6 +439,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Department",
|
||||
|
|
@ -453,6 +468,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Designation",
|
||||
|
|
@ -480,6 +496,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
|
|
@ -507,6 +524,7 @@
|
|||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Unsubscribed",
|
||||
|
|
@ -536,7 +554,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-01-13 06:59:06.417300",
|
||||
"modified": "2017-01-31 00:15:30.298287",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Contact",
|
||||
|
|
@ -552,7 +570,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -573,7 +590,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -594,7 +610,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -615,7 +630,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -636,7 +650,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -657,7 +670,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -678,7 +690,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -699,7 +710,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -720,7 +730,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -741,7 +750,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -762,7 +770,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
|
|
@ -783,7 +790,6 @@
|
|||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"match": "",
|
||||
"permlevel": 1,
|
||||
"print": 0,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from frappe.utils.fixtures import sync_fixtures
|
|||
from frappe.website import render
|
||||
from frappe.desk.doctype.desktop_icon.desktop_icon import sync_from_app
|
||||
from frappe.utils.password import create_auth_table
|
||||
from frappe.utils.global_search import setup_global_search_table
|
||||
from frappe.modules.utils import sync_customizations
|
||||
|
||||
def install_db(root_login="root", root_password=None, db_name=None, source_sql=None,
|
||||
|
|
@ -41,6 +42,7 @@ def install_db(root_login="root", root_password=None, db_name=None, source_sql=N
|
|||
remove_missing_apps()
|
||||
|
||||
create_auth_table()
|
||||
setup_global_search_table()
|
||||
create_list_settings_table()
|
||||
|
||||
frappe.flags.in_install_db = False
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from frappe.website import render
|
|||
from frappe.desk.doctype.desktop_icon.desktop_icon import sync_desktop_icons
|
||||
from frappe.core.doctype.language.language import sync_languages
|
||||
from frappe.modules.utils import sync_customizations
|
||||
import frappe.utils.help
|
||||
import frappe.utils.help
|
||||
|
||||
def migrate(verbose=True, rebuild_website=False):
|
||||
'''Migrate all apps to the latest version, will:
|
||||
|
|
|
|||
|
|
@ -12,9 +12,6 @@ no_value_fields = ('Section Break', 'Column Break', 'HTML', 'Table', 'Button', '
|
|||
display_fieldtypes = ('Section Break', 'Column Break', 'HTML', 'Button', 'Image', 'Fold', 'Heading')
|
||||
default_fields = ('doctype','name','owner','creation','modified','modified_by',
|
||||
'parent','parentfield','parenttype','idx','docstatus')
|
||||
integer_docfield_properties = ("reqd", "search_index", "in_list_view", "permlevel",
|
||||
"hidden", "read_only", "ignore_user_permissions", "allow_on_submit", "report_hide",
|
||||
"no_copy", "print_hide", "unique")
|
||||
optional_fields = ("_user_tags", "_comments", "_assign", "_liked_by", "_seen")
|
||||
|
||||
def rename(doctype, old, new, debug=False):
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from frappe.utils.file_manager import remove_all
|
|||
from frappe.utils.password import delete_all_passwords_for
|
||||
from frappe import _
|
||||
from frappe.model.naming import revert_series_if_last
|
||||
from frappe.utils.global_search import delete_for_document
|
||||
|
||||
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False,
|
||||
ignore_permissions=False, flags=None, ignore_on_trash=False):
|
||||
|
|
@ -87,6 +88,9 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
|
|||
# delete attachments
|
||||
remove_all(doctype, name, from_delete=True)
|
||||
|
||||
# delete global search entry
|
||||
delete_for_document(doc)
|
||||
|
||||
if doc and not for_reload:
|
||||
add_to_deleted_document(doc)
|
||||
if not frappe.flags.in_patch:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import time
|
||||
import redis
|
||||
from frappe import _, msgprint
|
||||
from frappe.utils import flt, cstr, now, get_datetime_str, file_lock
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
|
|
@ -13,7 +14,7 @@ from werkzeug.exceptions import NotFound, Forbidden
|
|||
import hashlib, json
|
||||
from frappe.model import optional_fields
|
||||
from frappe.utils.file_manager import save_url
|
||||
|
||||
from frappe.utils.global_search import update_global_search
|
||||
|
||||
# once_only validation
|
||||
# methods
|
||||
|
|
@ -789,6 +790,11 @@ class Document(BaseDocument):
|
|||
self.clear_cache()
|
||||
self.notify_update()
|
||||
|
||||
try:
|
||||
frappe.enqueue('frappe.utils.global_search.update_global_search', now=frappe.flags.in_test, doc=self)
|
||||
except redis.exceptions.ConnectionError:
|
||||
update_global_search(self)
|
||||
|
||||
if self._doc_before_save and not self.flags.ignore_version:
|
||||
self.save_version()
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Example:
|
|||
from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe.utils import cstr, cint
|
||||
from frappe.model import integer_docfield_properties, default_fields, no_value_fields, optional_fields
|
||||
from frappe.model import default_fields, no_value_fields, optional_fields
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.base_document import BaseDocument
|
||||
from frappe.model.db_schema import type_map
|
||||
|
|
@ -95,6 +95,14 @@ class Meta(Document):
|
|||
|
||||
return self._table_fields
|
||||
|
||||
def get_global_search_fields(self):
|
||||
'''Returns list of fields with `in_global_search` set and `name` if set'''
|
||||
fields = self.get("fields", {"in_global_search": 1 })
|
||||
if getattr(self, 'show_name_in_global_search', None):
|
||||
fields.append(frappe._dict(fieldtype='Data', fieldname='name', label='Name'))
|
||||
|
||||
return fields
|
||||
|
||||
def get_valid_columns(self):
|
||||
if not hasattr(self, "_valid_columns"):
|
||||
if self.name in ("DocType", "DocField", "DocPerm", "Property Setter"):
|
||||
|
|
@ -221,8 +229,15 @@ class Meta(Document):
|
|||
raise
|
||||
|
||||
def apply_property_setters(self):
|
||||
for ps in frappe.db.sql("""select * from `tabProperty Setter` where
|
||||
doc_type=%s""", (self.name,), as_dict=1):
|
||||
property_setters = frappe.db.sql("""select * from `tabProperty Setter` where
|
||||
doc_type=%s""", (self.name,), as_dict=1)
|
||||
|
||||
if not property_setters: return
|
||||
|
||||
integer_docfield_properties = [d.fieldname for d in frappe.get_meta('DocField').fields
|
||||
if d.fieldtype in ('Int', 'Check')]
|
||||
|
||||
for ps in property_setters:
|
||||
if ps.doctype_or_field=='DocType':
|
||||
if ps.property_type in ('Int', 'Check'):
|
||||
ps.value = cint(ps.value)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
execute:frappe.db.sql("""update `tabPatch Log` set patch=replace(patch, '.4_0.', '.v4_0.')""") #2014-05-12
|
||||
frappe.patches.v5_0.convert_to_barracuda_and_utf8mb4
|
||||
execute:frappe.utils.global_search.setup_global_search_table()
|
||||
frappe.patches.v7_0.update_auth
|
||||
frappe.patches.v7_1.rename_scheduler_log_to_error_log
|
||||
frappe.patches.v6_1.rename_file_data
|
||||
|
|
|
|||
|
|
@ -135,6 +135,9 @@
|
|||
"public/js/frappe/views/pageview.js",
|
||||
|
||||
"public/js/frappe/ui/toolbar/awesome_bar.js",
|
||||
"public/js/frappe/ui/toolbar/search.js",
|
||||
"public/js/frappe/ui/toolbar/search.html",
|
||||
"public/js/frappe/ui/toolbar/search_header.html",
|
||||
"public/js/frappe/ui/toolbar/about.js",
|
||||
"public/js/frappe/ui/toolbar/navbar.html",
|
||||
"public/js/frappe/ui/toolbar/toolbar.js",
|
||||
|
|
|
|||
|
|
@ -660,7 +660,79 @@ fieldset[disabled] .form-control {
|
|||
.note-editor .dropdown-menu {
|
||||
z-index: 100;
|
||||
max-height: 300px;
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
}
|
||||
.search-dialog .modal-dialog {
|
||||
width: 768px;
|
||||
height: 500px;
|
||||
}
|
||||
.search-dialog .modal-body {
|
||||
padding: 0px 15px;
|
||||
}
|
||||
.search-dialog input.form-control,
|
||||
.search-dialog .input-group-addon {
|
||||
border: none;
|
||||
border-left-style: none;
|
||||
}
|
||||
.search-dialog input.form-control:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.search-dialog .input-group-addon {
|
||||
background-color: #FFF;
|
||||
}
|
||||
.search-dialog .layout-side-section,
|
||||
.search-dialog .layout-main-section {
|
||||
height: 500px;
|
||||
padding: 0px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.search-dialog .layout-side-section {
|
||||
padding-left: 15px;
|
||||
}
|
||||
.search-dialog .module-section .back-link {
|
||||
margin-bottom: 20px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.search-dialog .module-section .all-results-link:before {
|
||||
font-family: 'Octicons';
|
||||
content: '\f0a4';
|
||||
}
|
||||
.search-dialog .dual-section .result a {
|
||||
color: black;
|
||||
}
|
||||
.search-dialog .dual-section .result a b {
|
||||
color: #4e6161;
|
||||
}
|
||||
.search-dialog .result-status {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.search-dialog .more-results {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.search-dialog .modal-dialog {
|
||||
width: auto;
|
||||
}
|
||||
.search-dialog .modal-content {
|
||||
height: auto !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.search-dialog .module-body {
|
||||
margin: 0px;
|
||||
border-top: none;
|
||||
}
|
||||
.search-dialog .layout-side-section .sidebar-menu {
|
||||
margin: 30px 0px;
|
||||
}
|
||||
}
|
||||
.result p {
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
.search-result {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.note-editor.note-frame .note-editing-area .note-editable {
|
||||
color: #36414C;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
frappe.provide('frappe.ui.misc');
|
||||
frappe.ui.misc.about = function() {
|
||||
if(!frappe.ui.misc.about_dialog) {
|
||||
var d = new frappe.ui.Dialog({title: __('Frappe Framework')})
|
||||
var d = new frappe.ui.Dialog({title: __('Frappe Framework')});
|
||||
|
||||
$(d.body).html(repl("<div>\
|
||||
<p>"+__("Open Source Applications for the Web")+"</p> \
|
||||
|
|
|
|||
|
|
@ -1,19 +1,38 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
frappe.provide('frappe.search');
|
||||
|
||||
frappe.search = {
|
||||
frappe.search.AwesomeBar = Class.extend({
|
||||
setup: function(element) {
|
||||
var $input = $(element);
|
||||
var input = $input.get(0);
|
||||
var me = this;
|
||||
this.search = new frappe.search.UnifiedSearch();
|
||||
this.global = new frappe.search.GlobalSearch();
|
||||
this.nav = new frappe.search.NavSearch();
|
||||
this.help = new frappe.search.HelpSearch();
|
||||
|
||||
var awesomplete = new Awesomplete(input, {
|
||||
minChars: 0,
|
||||
maxItems: 99,
|
||||
autoFirst: true,
|
||||
list: [],
|
||||
filter: function (text, term) { return true; },
|
||||
filter: function (text, term) {
|
||||
return true;
|
||||
},
|
||||
data: function (item, input) {
|
||||
var label = item.label + "%%%" + item.value + "%%%" +
|
||||
(item.description || "") + "%%%" + (item.index || "");
|
||||
return {
|
||||
label: label,
|
||||
value: item.value
|
||||
};
|
||||
},
|
||||
item: function(item, term) {
|
||||
var d = item;
|
||||
var parts = item.split("%%%"),
|
||||
d = { label: parts[0], value: parts[1], description: parts[2] };
|
||||
|
||||
var html = "<span>" + __(d.label || d.value) + "</span>";
|
||||
if(d.description && d.value!==d.description) {
|
||||
html += '<br><span class="text-muted">' + __(d.description) + '</span>';
|
||||
|
|
@ -23,57 +42,64 @@ frappe.search = {
|
|||
.html('<a style="font-weight:normal"><p>' + html + '</p></a>')
|
||||
.get(0);
|
||||
},
|
||||
sort: function(a, b) { return 0; }
|
||||
sort: function(a, b) {
|
||||
var a_index = a.split("%%%")[3];
|
||||
var b_index = b.split("%%%")[3];
|
||||
return (a_index - b_index);
|
||||
}
|
||||
});
|
||||
|
||||
$input.on("input", function(e) {
|
||||
var value = e.target.value;
|
||||
var txt = strip(value);
|
||||
frappe.search.options = [];
|
||||
if(txt) {
|
||||
var lower = strip(txt.toLowerCase());
|
||||
$.each(frappe.search.verbs, function(i, action) {
|
||||
action(lower);
|
||||
});
|
||||
}
|
||||
var $this = $(this);
|
||||
clearTimeout($this.data('timeout'));
|
||||
|
||||
// sort options
|
||||
frappe.search.options.sort(function(a, b) {
|
||||
return (a.match || "").length - (b.match || "").length; });
|
||||
|
||||
frappe.search.add_recent(txt || "");
|
||||
frappe.search.add_help();
|
||||
|
||||
// de-duplicate
|
||||
var out = [], routes = [];
|
||||
frappe.search.options.forEach(function(option) {
|
||||
if(option.route) {
|
||||
var str_route = (typeof option.route==='string') ?
|
||||
option.route : option.route.join('/');
|
||||
if(routes.indexOf(str_route)===-1) {
|
||||
out.push(option);
|
||||
routes.push(str_route);
|
||||
$this.data('timeout', setTimeout(function(){
|
||||
var value = e.target.value;
|
||||
var txt = strip(value);
|
||||
me.options = [];
|
||||
if(txt) {
|
||||
var keywords = strip(txt.toLowerCase());
|
||||
me.build_options(keywords);
|
||||
if(me.options.length < 2) {
|
||||
me.global.get_awesome_bar_options(keywords, me);
|
||||
}
|
||||
} else {
|
||||
out.push(option);
|
||||
}
|
||||
});
|
||||
awesomplete.list = out;
|
||||
|
||||
me.add_recent(txt || "");
|
||||
me.add_help();
|
||||
|
||||
// de-duplicate
|
||||
var out = [], routes = [];
|
||||
me.options.forEach(function(option) {
|
||||
if(option.route) {
|
||||
var str_route = (typeof option.route==='string') ?
|
||||
option.route : option.route.join('/');
|
||||
if(routes.indexOf(str_route)===-1) {
|
||||
out.push(option);
|
||||
routes.push(str_route);
|
||||
}
|
||||
} else {
|
||||
out.push(option);
|
||||
}
|
||||
});
|
||||
awesomplete.list = out;
|
||||
}, 200));
|
||||
|
||||
});
|
||||
|
||||
var open_recent = function() {
|
||||
if (!frappe.search.autocomplete_open) {
|
||||
if (!this.autocomplete_open) {
|
||||
$(this).trigger("input");
|
||||
}
|
||||
}
|
||||
$input.on("focus", open_recent);
|
||||
|
||||
$input.on("awesomplete-open", function(e) {
|
||||
frappe.search.autocomplete_open = e.target;
|
||||
me.autocomplete_open = e.target;
|
||||
});
|
||||
|
||||
$input.on("awesomplete-close", function(e) {
|
||||
frappe.search.autocomplete_open = false;
|
||||
me.autocomplete_open = false;
|
||||
});
|
||||
|
||||
$input.on("awesomplete-select", function(e) {
|
||||
|
|
@ -101,14 +127,15 @@ frappe.search = {
|
|||
$input.on("awesomplete-selectcomplete", function(e) {
|
||||
$input.val("");
|
||||
});
|
||||
|
||||
frappe.search.make_page_title_map();
|
||||
frappe.search.setup_recent();
|
||||
this.setup_recent();
|
||||
this.search.setup();
|
||||
},
|
||||
|
||||
add_help: function() {
|
||||
frappe.search.options.push({
|
||||
this.options.push({
|
||||
label: __("Help on Search"),
|
||||
value: "Help on Search",
|
||||
index: 20,
|
||||
onclick: function() {
|
||||
var txt = '<table class="table table-bordered">\
|
||||
<tr><td style="width: 50%">'+__("Make a new record")+'</td><td>'+
|
||||
|
|
@ -126,9 +153,11 @@ frappe.search = {
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
add_recent: function(txt) {
|
||||
var me = this;
|
||||
values = [];
|
||||
$.each(frappe.search.recent, function(i, doctype) {
|
||||
$.each(me.recent, function(i, doctype) {
|
||||
values.push([doctype[1], ['Form', doctype[0], doctype[1]]]);
|
||||
});
|
||||
|
||||
|
|
@ -148,7 +177,7 @@ frappe.search = {
|
|||
}
|
||||
});
|
||||
|
||||
frappe.search.find(values, txt, function(match) {
|
||||
this.find(values, txt, function(match) {
|
||||
out = {
|
||||
route: match[1]
|
||||
}
|
||||
|
|
@ -165,20 +194,13 @@ frappe.search = {
|
|||
out.label = match[0].bold();
|
||||
out.value = match[0];
|
||||
}
|
||||
out.index = 10
|
||||
return out;
|
||||
}, true);
|
||||
},
|
||||
make_page_title_map: function() {
|
||||
frappe.search.pages = {};
|
||||
$.each(frappe.boot.page_info, function(name, p) {
|
||||
frappe.search.pages[p.title] = p;
|
||||
p.name = name;
|
||||
});
|
||||
},
|
||||
setup_recent: function() {
|
||||
frappe.search.recent = JSON.parse(frappe.boot.user.recent || "[]") || [];
|
||||
},
|
||||
|
||||
find: function(list, txt, process, prepend) {
|
||||
var me = this;
|
||||
$.each(list, function(i, item) {
|
||||
if($.isArray(item)) {
|
||||
_item = item[0];
|
||||
|
|
@ -197,19 +219,60 @@ frappe.search = {
|
|||
option.forEach(function(o) { o.match = item; });
|
||||
|
||||
if(prepend) {
|
||||
frappe.search.options = option.concat(frappe.search.options);
|
||||
me.options = option.concat(me.options);
|
||||
} else {
|
||||
frappe.search.options = frappe.search.options.concat(option);
|
||||
me.options = me.options.concat(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
frappe.search.verbs = [
|
||||
// search in list if current
|
||||
function(txt) {
|
||||
setup_recent: function() {
|
||||
this.recent = JSON.parse(frappe.boot.user.recent || "[]") || [];
|
||||
},
|
||||
|
||||
is_present: function(txt, item) {
|
||||
($.isArray(item)) ? _item = item[0] : _item = item;
|
||||
_item = __(_item || '').toLowerCase().replace(/-/g, " ");
|
||||
if(txt===_item || _item.indexOf(txt) !== -1) {
|
||||
return item;
|
||||
}
|
||||
},
|
||||
|
||||
set_global_results: function(global_results){
|
||||
this.options = this.options.concat(global_results);
|
||||
},
|
||||
|
||||
build_options: function(txt) {
|
||||
this.options =
|
||||
this.make_global_search(txt).concat(
|
||||
this.make_search_in_current(txt),
|
||||
this.make_calculator(txt),
|
||||
this.make_new_doc(txt),
|
||||
this.make_search_in_list(txt),
|
||||
this.get_doctypes(txt),
|
||||
this.get_reports(txt),
|
||||
this.get_pages(txt),
|
||||
this.get_modules(txt)
|
||||
);
|
||||
},
|
||||
|
||||
make_global_search: function(txt) {
|
||||
var me = this;
|
||||
return [{
|
||||
label: __("Search for '" + txt.bold() + "'"),
|
||||
value: __("Search for '" + txt + "'"),
|
||||
match: txt,
|
||||
index: 5,
|
||||
onclick: function() {
|
||||
me.search.search_dialog.show();
|
||||
me.search.setup_search(txt, [me.global, me.nav, me.help]);
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
make_search_in_current: function(txt) {
|
||||
var route = frappe.get_route();
|
||||
if(route[0]==="List" && txt.indexOf(" in") === -1) {
|
||||
// search in title field
|
||||
|
|
@ -217,183 +280,224 @@ frappe.search.verbs = [
|
|||
var search_field = meta.title_field || "name";
|
||||
var options = {};
|
||||
options[search_field] = ["like", "%" + txt + "%"];
|
||||
frappe.search.options.push({
|
||||
return [{
|
||||
label: __('Find {0} in {1}', [txt.bold(), route[1].bold()]),
|
||||
value: __('Find {0} in {1}', [txt, route[1]]),
|
||||
route_options: options,
|
||||
index: 10,
|
||||
onclick: function() {
|
||||
cur_list.refresh();
|
||||
},
|
||||
match: txt
|
||||
});
|
||||
}
|
||||
}];
|
||||
} else { return []; }
|
||||
},
|
||||
|
||||
// new doc
|
||||
function(txt) {
|
||||
var ret = false;
|
||||
if(txt.split(" ")[0]==="new") {
|
||||
frappe.search.find(frappe.boot.user.can_create, txt.substr(4), function(match) {
|
||||
return {
|
||||
label: __("New {0}", [match.bold()]),
|
||||
value: __("New {0}", [match]),
|
||||
onclick: function() { frappe.new_doc(match, true); }
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// doctype list
|
||||
function(txt) {
|
||||
if (txt.toLowerCase().indexOf(" list")) {
|
||||
// remove list keyword
|
||||
txt = txt.replace(/ list/ig, "").trim();
|
||||
}
|
||||
|
||||
frappe.search.find(frappe.boot.user.can_read, txt, function(match) {
|
||||
if(in_list(frappe.boot.single_types, match)) {
|
||||
return {
|
||||
label: __("{0}", [__(match).bold()]),
|
||||
value: __(match),
|
||||
route:["Form", match, match]
|
||||
}
|
||||
} else if(in_list(frappe.boot.treeviews, match)) {
|
||||
return {
|
||||
label: __("{0} Tree", [__(match).bold()]),
|
||||
value: __(match),
|
||||
route:["Tree", match]
|
||||
}
|
||||
} else {
|
||||
out = [
|
||||
{
|
||||
label: __("{0} List", [__(match).bold()]),
|
||||
value: __("{0} List", [__(match)]),
|
||||
route:["List", match]
|
||||
},
|
||||
];
|
||||
if(frappe.model.can_get_report(match)) {
|
||||
out.push({
|
||||
label: __("{0} Report", [__(match).bold()]),
|
||||
value: __("{0} Report", [__(match)]),
|
||||
route:["Report", match]
|
||||
});
|
||||
}
|
||||
if(frappe.boot.calendars.indexOf(match) !== -1) {
|
||||
out.push({
|
||||
label: __("{0} Calendar", [__(match).bold()]),
|
||||
value: __("{0} Calendar", [__(match)]),
|
||||
route:["List", match, "Calendar"]
|
||||
});
|
||||
|
||||
out.push({
|
||||
label: __("{0} Gantt", [__(match).bold()]),
|
||||
value: __("{0} Gantt", [__(match)]),
|
||||
route:["List", match, "Gantt"]
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// reports
|
||||
function(txt) {
|
||||
frappe.search.find(keys(frappe.boot.user.all_reports), txt, function(match) {
|
||||
var report = frappe.boot.user.all_reports[match];
|
||||
var route = [];
|
||||
if(report.report_type == "Report Builder")
|
||||
route = ["Report", report.ref_doctype, match];
|
||||
else
|
||||
route = ["query-report", match];
|
||||
|
||||
return {
|
||||
label: __("Report {0}", [__(match).bold()]),
|
||||
value: __("Report {0}", [__(match)]),
|
||||
route: route
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// pages
|
||||
function(txt) {
|
||||
frappe.search.find(keys(frappe.search.pages), txt, function(match) {
|
||||
return {
|
||||
label: __("Open {0}", [__(match).bold()]),
|
||||
value: __("Open {0}", [__(match)]),
|
||||
route: [frappe.search.pages[match].route || frappe.search.pages[match].name]
|
||||
}
|
||||
});
|
||||
|
||||
// calendar
|
||||
var match = 'Calendar';
|
||||
if(__('calendar').indexOf(txt.toLowerCase()) === 0) {
|
||||
frappe.search.options.push({
|
||||
label: __("Open {0}", [__(match).bold()]),
|
||||
value: __("Open {0}", [__(match)]),
|
||||
route: ['List', 'Event', 'Calendar'],
|
||||
match: match
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// modules
|
||||
function(txt) {
|
||||
frappe.search.find(keys(frappe.modules), txt, function(match) {
|
||||
var module = frappe.modules[match];
|
||||
|
||||
if(module._doctype) return;
|
||||
|
||||
ret = {
|
||||
label: __("Open {0}", [__(match).bold()]),
|
||||
value: __("Open {0}", [__(match)]),
|
||||
}
|
||||
if(module.link) {
|
||||
ret.route = [module.link];
|
||||
} else {
|
||||
ret.route = ["Module", match];
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
},
|
||||
|
||||
// in
|
||||
function(txt) {
|
||||
if(in_list(txt.split(" "), "in")) {
|
||||
parts = txt.split(" in ");
|
||||
frappe.search.find(frappe.boot.user.can_read, parts[1], function(match) {
|
||||
return {
|
||||
label: __('Find {0} in {1}', [__(parts[0]).bold(), __(match).bold()]),
|
||||
value: __('Find {0} in {1}', [__(parts[0]), __(match)]),
|
||||
route_options: {"name": ["like", "%" + parts[0] + "%"]},
|
||||
route: ["List", match]
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// calculator
|
||||
function(txt) {
|
||||
make_calculator: function(txt) {
|
||||
var first = txt.substr(0,1);
|
||||
if(first==parseInt(first) || first==="(" || first==="=") {
|
||||
if(first==="=") {
|
||||
txt = txt.substr(1);
|
||||
}
|
||||
|
||||
try {
|
||||
var val = eval(txt);
|
||||
var formatted_value = __('{0} = {1}', [txt, (val + '').bold()]);
|
||||
frappe.search.options.push({
|
||||
return [{
|
||||
label: formatted_value,
|
||||
value: __('{0} = {1}', [txt, val]),
|
||||
match: val,
|
||||
onclick: function(match) {
|
||||
index: 10,
|
||||
onclick: function() {
|
||||
msgprint(formatted_value, "Result");
|
||||
}
|
||||
});
|
||||
}];
|
||||
} catch(e) {
|
||||
// pass
|
||||
}
|
||||
} else { return []; }
|
||||
},
|
||||
|
||||
make_new_doc: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
if(txt.split(" ")[0]==="new") {
|
||||
frappe.boot.user.can_create.forEach(function (item) {
|
||||
var target = me.is_present(txt.substr(4), item);
|
||||
if(target) {
|
||||
out.push({
|
||||
label: __("New {0}", [target.bold()]),
|
||||
value: __("New {0}", [target]),
|
||||
index: 10,
|
||||
match: target,
|
||||
onclick: function() { frappe.new_doc(target, true); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
make_search_in_list: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
if(in_list(txt.split(" "), "in")) {
|
||||
parts = txt.split(" in ");
|
||||
frappe.boot.user.can_read.forEach(function (item) {
|
||||
target = me.is_present(parts[1], item);
|
||||
if(target) {
|
||||
out.push({
|
||||
label: __('Find {0} in {1}', [__(parts[0]).bold(), __(target).bold()]),
|
||||
value: __('Find {0} in {1}', [__(parts[0]), __(target)]),
|
||||
route_options: {"name": ["like", "%" + parts[0] + "%"]},
|
||||
index: 10,
|
||||
route: ["List", target]
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
get_doctypes: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
|
||||
var target, index;
|
||||
var option = function(type, route) {
|
||||
return {
|
||||
label: __("{0} " + type, [__(target).bold()]),
|
||||
value: __(target),
|
||||
route: route,
|
||||
index: index,
|
||||
match: target
|
||||
}
|
||||
};
|
||||
}
|
||||
];
|
||||
frappe.boot.user.can_read.forEach(function (item) {
|
||||
target = me.is_present(txt, item);
|
||||
if(target) {
|
||||
var match_ratio = txt.length / item.length;
|
||||
index = (match_ratio > 0.7) ? 10 : 12;
|
||||
|
||||
// include 'making new' option
|
||||
if(in_list(frappe.boot.user.can_create, target)) {
|
||||
out.push({
|
||||
label: __("New {0}", [target.bold()]),
|
||||
value: __("New {0}", [target]),
|
||||
match: target,
|
||||
index: 12,
|
||||
onclick: function() { frappe.new_doc(target, true); }
|
||||
});
|
||||
}
|
||||
if(in_list(frappe.boot.single_types, target)) {
|
||||
out.push(option("", ["Form", target, target]));
|
||||
|
||||
} else if(in_list(frappe.boot.treeviews, target)) {
|
||||
out.push(option("Tree", ["Tree", target]));
|
||||
|
||||
} else {
|
||||
out.push(option("List", ["List", target]));
|
||||
if(frappe.model.can_get_report(target)) {
|
||||
out.push(option("Report", ["Report", target]));
|
||||
}
|
||||
if(frappe.boot.calendars.indexOf(target) !== -1) {
|
||||
out.push(option("Calendar", ["List", target, "Calendar"]));
|
||||
out.push(option("Gantt", ["List", target, "Gantt"]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
return out;
|
||||
},
|
||||
|
||||
get_reports: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
Object.keys(frappe.boot.user.all_reports).forEach(function(item) {
|
||||
var target = me.is_present(txt, item);
|
||||
if(target) {
|
||||
var report = frappe.boot.user.all_reports[target];
|
||||
var match_ratio = txt.length / item.length;
|
||||
var index = (match_ratio > 0.7) ? 10 : 13;
|
||||
var route = [];
|
||||
if(report.report_type == "Report Builder")
|
||||
route = ["Report", report.ref_doctype, target];
|
||||
else
|
||||
route = ["query-report", target];
|
||||
|
||||
out.push({
|
||||
label: __("Report {0}", [__(target).bold()]),
|
||||
value: __("Report {0}" , [__(target)]),
|
||||
match: txt,
|
||||
index: index,
|
||||
route: route
|
||||
});
|
||||
}
|
||||
});
|
||||
return out;
|
||||
},
|
||||
|
||||
get_pages: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
this.pages = {};
|
||||
$.each(frappe.boot.page_info, function(name, p) {
|
||||
me.pages[p.title] = p;
|
||||
p.name = name;
|
||||
});
|
||||
Object.keys(this.pages).forEach(function(item) {
|
||||
var target = me.is_present(txt, item);
|
||||
if(target) {
|
||||
var match_ratio = txt.length / item.length;
|
||||
var index = (match_ratio > 0.7) ? 10 : 14;
|
||||
var page = me.pages[target];
|
||||
out.push({
|
||||
label: __("Open {0}", [__(target).bold()]),
|
||||
value: __("Open {0}", [__(target)]),
|
||||
match: txt,
|
||||
index: index,
|
||||
route: [page.route || page.name]
|
||||
});
|
||||
}
|
||||
});
|
||||
// calendar
|
||||
var target = 'Calendar';
|
||||
if(__('calendar').indexOf(txt.toLowerCase()) === 0) {
|
||||
out.push({
|
||||
label: __("Open {0}", [__(target).bold()]),
|
||||
value: __("Open {0}", [__(target)]),
|
||||
route: [target, 'Event'],
|
||||
index: 14,
|
||||
match: target
|
||||
});
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
get_modules: function(txt) {
|
||||
var me = this;
|
||||
var out = [];
|
||||
Object.keys(frappe.modules).forEach(function(item) {
|
||||
var target = me.is_present(txt, item);
|
||||
if(target) {
|
||||
var match_ratio = txt.length / item.length;
|
||||
var index = (match_ratio > 0.7) ? 10 : 15;
|
||||
var module = frappe.modules[target];
|
||||
if(module._doctype) return;
|
||||
ret = {
|
||||
label: __("Open {0}", [__(target).bold()]),
|
||||
value: __("Open {0}", [__(target)]),
|
||||
match: txt,
|
||||
index: index
|
||||
}
|
||||
if(module.link) {
|
||||
ret.route = [module.link];
|
||||
} else {
|
||||
ret.route = ["Module", target];
|
||||
}
|
||||
out.push(ret);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
},
|
||||
});
|
||||
|
|
|
|||
11
frappe/public/js/frappe/ui/toolbar/search.html
Normal file
11
frappe/public/js/frappe/ui/toolbar/search.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<div class="row">
|
||||
<div class="col-md-2 col-sm-2 hidden-xs layout-side-section search-sidebar">
|
||||
</div>
|
||||
<div class="col-md-10 col-sm-10 layout-main-section results-area">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
644
frappe/public/js/frappe/ui/toolbar/search.js
Normal file
644
frappe/public/js/frappe/ui/toolbar/search.js
Normal file
|
|
@ -0,0 +1,644 @@
|
|||
frappe.provide('frappe.search');
|
||||
|
||||
frappe.search.UnifiedSearch = Class.extend({
|
||||
|
||||
setup: function() {
|
||||
var d = new frappe.ui.Dialog();
|
||||
$(frappe.render_template("search")).appendTo($(d.body));
|
||||
$(d.header).html($(frappe.render_template("search_header")));
|
||||
|
||||
this.search_dialog = d;
|
||||
this.search_modal = $(d.$wrapper);
|
||||
this.search_modal.addClass('search-dialog');
|
||||
|
||||
this.input = this.search_modal.find(".search-input");
|
||||
this.sidebar = this.search_modal.find(".search-sidebar");
|
||||
this.results_area = this.search_modal.find(".results-area");
|
||||
},
|
||||
|
||||
setup_search: function(keywords, search_objects) {
|
||||
var me = this;
|
||||
this.search_objects = search_objects;
|
||||
this.search_types = search_objects.map(function(s) {
|
||||
return s.search_type;
|
||||
});
|
||||
this.current_type = '';
|
||||
this.reset();
|
||||
this.input.val(keywords);
|
||||
this.input.on("input", function() {
|
||||
var $this = $(this);
|
||||
clearTimeout($this.data('timeout'));
|
||||
|
||||
$this.data('timeout', setTimeout(function(){
|
||||
var keywords = me.input.val();
|
||||
me.reset();
|
||||
if(keywords.length > 1) {
|
||||
me.build_results(keywords);
|
||||
} else {
|
||||
me.current_type = '';
|
||||
}
|
||||
}, 250));
|
||||
});
|
||||
this.build_results(keywords);
|
||||
setTimeout(function() { me.input.select(); }, 500);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.sidebar.empty();
|
||||
this.results_area.empty();
|
||||
},
|
||||
|
||||
build_results: function(keywords) {
|
||||
var me = this;
|
||||
this.summary = $('<div class="module-body summary"></div>');
|
||||
this.full_lists = {};
|
||||
this.current = 0;
|
||||
this.search_objects[me.current].build_results_object(me, keywords);
|
||||
},
|
||||
|
||||
render_results: function(results_obj, keywords){
|
||||
var me = this;
|
||||
if(this.current === 0) { this.reset() }
|
||||
this.sidebar.append(results_obj.sidelist);
|
||||
this.results_area.find('.results-status').remove();
|
||||
results_obj.sections.forEach(function(section) {
|
||||
me.summary.append(section);
|
||||
});
|
||||
this.full_lists = Object.assign(this.full_lists, results_obj.lists);
|
||||
this.render_next_search(keywords);
|
||||
},
|
||||
|
||||
bind_events: function() {
|
||||
var me = this;
|
||||
this.sidebar.find('.list-link').on('click', function() {
|
||||
me.set_sidebar_link_action($(this));
|
||||
});
|
||||
this.results_area.find('.section-more').on('click', function() {
|
||||
var type = $(this).attr('data-category');
|
||||
me.sidebar.find('*[data-category="'+ type +'"]').trigger('click');
|
||||
});
|
||||
},
|
||||
|
||||
set_sidebar_link_action: function(link) {
|
||||
this.sidebar.find(".list-link a").removeClass("disabled");
|
||||
link.find('a').addClass("disabled");
|
||||
var type = link.attr('data-category');
|
||||
this.results_area.empty().html(this.full_lists[type]);
|
||||
|
||||
this.current_type = type;
|
||||
|
||||
this.set_back_link();
|
||||
this.set_list_more_link(type);
|
||||
},
|
||||
|
||||
set_back_link: function() {
|
||||
var me = this;
|
||||
var back_link = this.results_area.find('.all-results-link');
|
||||
back_link.on('click', function() {
|
||||
me.show_summary();
|
||||
});
|
||||
},
|
||||
|
||||
show_summary: function() {
|
||||
this.current_type = '';
|
||||
this.results_area.empty().html(this.summary);
|
||||
this.bind_events();
|
||||
},
|
||||
|
||||
set_list_more_link: function(type) {
|
||||
var me = this;
|
||||
var more_link = this.results_area.find('.list-more');
|
||||
more_link.on('click', function() {
|
||||
var more_search_type = $(this).attr('data-search');
|
||||
var s_obj = me.search_objects[me.search_types.indexOf(more_search_type)];
|
||||
s_obj.get_more_results(type);
|
||||
});
|
||||
},
|
||||
|
||||
add_more_results: function(more_data) {
|
||||
var me = this;
|
||||
var more_results = more_data[0];
|
||||
var more = more_data[1];
|
||||
this.results_area.find('.list-more').before(more_results);
|
||||
if(!more) {
|
||||
this.results_area.find('.list-more').hide();
|
||||
var no_of_results = this.results_area.find('.result').length;
|
||||
var no_of_results_cue = $('<p class="results-status text-muted small">'+
|
||||
no_of_results +' results found</p>');
|
||||
this.results_area.find(".result:last").append(no_of_results_cue);
|
||||
}
|
||||
this.results_area.find('.more-results.last').slideDown(200, function() {
|
||||
var height = me.results_area.find('.module-body').height() - 750;
|
||||
if(me.results_area.find('.list-more').is(":visible")) {
|
||||
me.results_area.animate({
|
||||
scrollTop: height
|
||||
}, 300);
|
||||
}
|
||||
$(this).removeClass('last');
|
||||
});
|
||||
},
|
||||
|
||||
render_next_search: function(keywords) {
|
||||
this.current += 1;
|
||||
if(this.current < this.search_objects.length){
|
||||
// More searches to go
|
||||
this.search_objects[this.current].build_results_object(this, keywords);
|
||||
} else {
|
||||
// If there's only one link in sidebar, there's no summary (show its full list)
|
||||
if(this.sidebar.find('.list-link').length === 1) {
|
||||
this.bind_events();
|
||||
this.sidebar.find('.list-link').trigger('click');
|
||||
this.results_area.find('.all-results-link').hide();
|
||||
|
||||
} else if (this.sidebar.find('.list-link').length === 0) {
|
||||
this.results_area.html('<p class="results-status text-muted" style="text-align: center;">'+
|
||||
'No results found for: '+ "'"+ keywords +"'" +'</p>');
|
||||
} else {
|
||||
var list_types = this.get_all_list_types();
|
||||
if(list_types.indexOf(this.current_type) >= 0) {
|
||||
this.bind_events();
|
||||
this.sidebar.find('*[data-category="'+ this.current_type +'"]').trigger('click');
|
||||
} else {
|
||||
this.show_summary();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
get_all_list_types: function() {
|
||||
var types = [];
|
||||
this.sidebar.find('.list-link').each(function() {
|
||||
types.push($(this).attr('data-category'));
|
||||
});
|
||||
return types;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
frappe.search.GlobalSearch = Class.extend({
|
||||
init: function() {
|
||||
this.search_type = 'Global Search';
|
||||
},
|
||||
|
||||
setup: function() {
|
||||
this.types = [];
|
||||
this.sections = [];
|
||||
this.lists = {};
|
||||
this.more_length = 15;
|
||||
this.start = {};
|
||||
this.section_length = 3;
|
||||
|
||||
this.set_types();
|
||||
},
|
||||
|
||||
set_types: function() {
|
||||
var me = this;
|
||||
this.current_type = 0;
|
||||
frappe.call({
|
||||
method: "frappe.utils.global_search.get_search_doctypes",
|
||||
args: { text: me.keywords },
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
r.message.forEach(function(d) {
|
||||
me.types.push(d.doctype);
|
||||
me.start[d.doctype] = 0;
|
||||
});
|
||||
me.sidelist = me.make_sidelist();
|
||||
me.get_result_set(me.types[me.current_type]);
|
||||
} else {
|
||||
me.render_object.render_next_search(me.keywords);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
make_sidelist: function() {
|
||||
var me = this;
|
||||
var sidelist = $('<ul class="list-unstyled sidebar-menu nav-list"></ul>');
|
||||
sidelist.append('<li class="h6">'+ me.search_type +'</li>');
|
||||
this.types.forEach(function(type) {
|
||||
sidelist.append(me.make_sidelist_item(type));
|
||||
});
|
||||
sidelist.append('<li class="divider"></li>');
|
||||
return sidelist;
|
||||
},
|
||||
|
||||
make_sidelist_item: function(type) {
|
||||
var sidelist_item = '<li class="list-link" data-search="{0}"' +
|
||||
'data-category="{1}"><a>{1}</a></li>';
|
||||
return $(__(sidelist_item, [this.search_type, type]));
|
||||
},
|
||||
|
||||
get_result_set: function(doctype){
|
||||
var me = this;
|
||||
var more = true;
|
||||
frappe.call({
|
||||
method: "frappe.utils.global_search.search_in_doctype",
|
||||
args: {
|
||||
doctype: doctype,
|
||||
text: me.keywords,
|
||||
start: me.start[doctype],
|
||||
limit: me.more_length,
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
me.start[doctype] += me.more_length;
|
||||
if(r.message.length < me.more_length) {
|
||||
more = false;
|
||||
}
|
||||
me.make_type_results(doctype, r.message, more);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
make_type_results: function(type, results, more) {
|
||||
var last_type = (type == this.types.slice(-1));
|
||||
this.sections.push(this.make_section(type, results));
|
||||
this.lists[type] = this.make_full_list(type, results, more);
|
||||
if(!last_type) {
|
||||
this.current_type += 1;
|
||||
this.get_result_set(this.types[this.current_type]);
|
||||
} else {
|
||||
this.render_results();
|
||||
}
|
||||
},
|
||||
|
||||
build_results_object: function(r, keywords) {
|
||||
this.render_object = r;
|
||||
this.keywords = keywords;
|
||||
this.setup();
|
||||
},
|
||||
|
||||
render_results: function() {
|
||||
var me = this;
|
||||
if(this.sections.length > 0) {
|
||||
this.render_object.render_results({
|
||||
sidelist: me.sidelist,
|
||||
sections: me.sections,
|
||||
lists: me.lists
|
||||
}, me.keywords);
|
||||
}
|
||||
},
|
||||
|
||||
make_result_item: function(type, result) {
|
||||
var link_html = '<div class="result '+ type +'-result">' +
|
||||
'<a href="{0}" class="module-section-link small">{1}</a>' +
|
||||
'<p class="small">{2}</p>' +
|
||||
'</div>';
|
||||
var formatted_result = this.format_result(result);
|
||||
return $(__(link_html, formatted_result));
|
||||
},
|
||||
|
||||
format_result: function(result) {
|
||||
var route = '#Form/' + result.doctype + '/' + result.name;
|
||||
return [route, this.bold_keywords(result.name),
|
||||
this.get_finds(result.content, this.keywords)]
|
||||
},
|
||||
|
||||
get_finds: function(searchables, keywords) {
|
||||
var me = this;
|
||||
parts = searchables.split("|||");
|
||||
content = "";
|
||||
parts.forEach(function(part) {
|
||||
if(part.toLowerCase().indexOf(keywords) !== -1) {
|
||||
var colon_index = part.indexOf(':');
|
||||
part = '<span class="field-name text-muted">' +
|
||||
part.slice(0, colon_index + 1) + '</span>' +
|
||||
me.bold_keywords(part.slice(colon_index + 1), keywords);
|
||||
content += part + ', ';
|
||||
}
|
||||
});
|
||||
return content.slice(0, -2);
|
||||
},
|
||||
|
||||
bold_keywords: function(str, keywords) {
|
||||
var regEx = new RegExp("("+ keywords +")", "ig");
|
||||
return str.replace(regEx, '<b>$1</b>');
|
||||
},
|
||||
|
||||
make_section: function(type, results) {
|
||||
var me = this;
|
||||
var results_section = $('<div class="row module-section '+type+'-section">'+
|
||||
'<div class="col-sm-12 module-section-column">' +
|
||||
'<div class="h4 section-head">'+type+'</div>' +
|
||||
'<div class="section-body"></div>'+
|
||||
'</div></div>');
|
||||
var results_col = results_section.find('.module-section-column');
|
||||
results.slice(0, this.section_length).forEach(function(result) {
|
||||
results_col.append(me.make_result_item(type, result));
|
||||
});
|
||||
if(results.length > this.section_length) {
|
||||
results_col.append('<a class="small section-more" data-category="'
|
||||
+ type + '">More...</a>');
|
||||
}
|
||||
return results_section;
|
||||
},
|
||||
|
||||
make_full_list: function(type, results, more) {
|
||||
var me = this;
|
||||
var results_list = $(' <div class="module-body"><div class="row module-section '+
|
||||
type+'-section">'+'<div class="col-sm-12 module-section-column">' +
|
||||
'<div class="back-link"><a class="all-results-link small"> All Results</a></div>' +
|
||||
'<div class="h4 section-head">'+type+'</div>' +
|
||||
'<div class="section-body"></div>'+
|
||||
'</div></div></div>');
|
||||
var results_col = results_list.find('.module-section-column');
|
||||
results.forEach(function(result) {
|
||||
results_col.append(me.make_result_item(type, result));
|
||||
});
|
||||
if(more) {
|
||||
results_col.append('<a class="small list-more" data-search="'+ this.search_type +'" data-category="'
|
||||
+ type + '">More...</a>');
|
||||
}
|
||||
return results_list;
|
||||
},
|
||||
|
||||
get_more_results: function(doctype) {
|
||||
var me = this;
|
||||
var more = true;
|
||||
frappe.call({
|
||||
method: "frappe.utils.global_search.search_in_doctype",
|
||||
args: {
|
||||
doctype: doctype,
|
||||
text: me.keywords,
|
||||
start: me.start[doctype],
|
||||
limit: me.more_length,
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
me.start[doctype] += me.more_length;
|
||||
me.make_more_list(doctype, r.message, more);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
make_more_list: function(type, results, more) {
|
||||
var me = this;
|
||||
if(results.length < this.more_length) { more = false; }
|
||||
|
||||
var more_results = $('<div class="more-results last"></div>');
|
||||
results.forEach(function(result) {
|
||||
more_results.append(me.make_result_item(type, result));
|
||||
});
|
||||
this.render_object.add_more_results([more_results, more]);
|
||||
},
|
||||
|
||||
get_awesome_bar_options: function(keywords, ref) {
|
||||
|
||||
var me = this;
|
||||
var doctypes = [];
|
||||
var current = 0;
|
||||
var results = [];
|
||||
|
||||
var get_doctypes = function(){
|
||||
var me = this;
|
||||
frappe.call({
|
||||
method: "frappe.utils.global_search.get_search_doctypes",
|
||||
args: { text: keywords },
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
r.message.forEach(function(d) {
|
||||
doctypes.push(d.doctype);
|
||||
});
|
||||
get_results();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var get_results = function() {
|
||||
frappe.call({
|
||||
method: "frappe.utils.global_search.search_in_doctype",
|
||||
args: {
|
||||
doctype: doctypes[current],
|
||||
text: keywords,
|
||||
start: 0,
|
||||
limit: 4,
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
r.message.forEach(function(d) {
|
||||
results.push(make_option(d));
|
||||
});
|
||||
current += 1;
|
||||
if(current < doctypes.length) {
|
||||
get_results();
|
||||
} else {
|
||||
ref.set_global_results(results);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var make_option = function(data) {
|
||||
console.log("GS search", me.get_finds(data.content, keywords).slice(0,86) + '...');
|
||||
return {
|
||||
label: __("{0}: {1}", [__(data.doctype).bold(), data.name]),
|
||||
value: __("{0}: {1}", [__(data.doctype), data.name]),
|
||||
route: ["Form", data.doctype, data.name],
|
||||
match: data.doctype,
|
||||
index: 5,
|
||||
description: me.get_finds(data.content, keywords).slice(0,86) + '...'
|
||||
}
|
||||
};
|
||||
|
||||
get_doctypes();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
frappe.search.NavSearch = frappe.search.GlobalSearch.extend({
|
||||
init: function() {
|
||||
this.search_type = 'Navigation';
|
||||
},
|
||||
|
||||
set_types: function() {
|
||||
var me = this;
|
||||
this.section_length = 4;
|
||||
this.awesome_bar = new frappe.search.AwesomeBar();
|
||||
this.nav_results = {
|
||||
"Search in ...": me.awesome_bar.make_search_in_list(me.keywords),
|
||||
"Lists": me.awesome_bar.get_doctypes(me.keywords),
|
||||
"Reports": me.awesome_bar.get_reports(me.keywords),
|
||||
"Pages": me.awesome_bar.get_pages(me.keywords),
|
||||
"Modules": me.awesome_bar.get_modules(me.keywords)
|
||||
}
|
||||
var types = ["Search in ...", "Lists", "Reports", "Pages", "Modules"];
|
||||
types.forEach(function(type) {
|
||||
if(me.nav_results[type].length > 0) {
|
||||
me.types.push(type);
|
||||
me.start[type] = 0;
|
||||
}
|
||||
});
|
||||
if(this.types.length > 0) {
|
||||
this.sidelist = this.make_sidelist();
|
||||
this.get_results();
|
||||
} else {
|
||||
this.render_object.render_next_search(me.keywords);
|
||||
}
|
||||
},
|
||||
|
||||
get_results: function() {
|
||||
var me = this;
|
||||
this.types.forEach(function(type) {
|
||||
me.get_result_set(type);
|
||||
});
|
||||
},
|
||||
|
||||
get_result_set: function(type) {
|
||||
var last_type = (type == this.types.slice(-1));
|
||||
var results = this.nav_results[type].slice(this.start[type], this.more_length);
|
||||
this.start[type] += this.more_length;
|
||||
var more = true;
|
||||
if(results.slice(-1)[0] === this.nav_results[type].slice(-1)[0]) {
|
||||
more = false;
|
||||
}
|
||||
this.make_type_results(type, results, more);
|
||||
if(last_type) {
|
||||
this.render_results();
|
||||
}
|
||||
},
|
||||
|
||||
make_type_results: function(type, results, more) {
|
||||
this.sections.push(this.make_section(type, results));
|
||||
this.lists[type] = this.make_full_list(type, results, more);
|
||||
},
|
||||
|
||||
get_more_results: function(type) {
|
||||
var results = this.nav_results[type].slice(this.start[type],
|
||||
this.start[type]+this.more_length);
|
||||
this.start[type] += this.more_length;
|
||||
var more = true;
|
||||
if(results.slice(-1)[0] === this.nav_results[type].slice(-1)[0]) {
|
||||
more = false;
|
||||
}
|
||||
this.make_more_list(type, results, more)
|
||||
},
|
||||
|
||||
make_result_item: function(type, result) {
|
||||
var link_html = '<div class="result '+ type +'-result single-link">' +
|
||||
'<a href="{0}" class="module-section-link small">{1}</a>' +
|
||||
'<p class="small"></p></div>';
|
||||
if(!result.onclick) {
|
||||
var link = $(__(link_html, ['#', result.label]));
|
||||
link.on('click', function() {
|
||||
if(result.route_options) {
|
||||
frappe.route_options = result.route_options;
|
||||
}
|
||||
frappe.set_route(result.route);
|
||||
return false;
|
||||
});
|
||||
return link;
|
||||
} else {
|
||||
var link = $(__(link_html, ['#', result.label]));
|
||||
link.on('click', function() {
|
||||
frappe.new_doc(result.match, true);
|
||||
// result.onclick(result.match, true);
|
||||
});
|
||||
return link;
|
||||
}
|
||||
},
|
||||
|
||||
make_dual_sections: function() {
|
||||
this.dual_sections = [];
|
||||
var section_html = '<div class="row module-section dual-section"></div>';
|
||||
for(var i = 0; i < this.sections.length; i++) {
|
||||
var results_section = $(section_html);
|
||||
for(var j = 0; j < 2 && i < this.sections.length; j++, i++){
|
||||
results_section.append(this.sections[i]);
|
||||
}
|
||||
i--;
|
||||
this.dual_sections.push(results_section);
|
||||
}
|
||||
},
|
||||
|
||||
render_results: function() {
|
||||
var me = this;
|
||||
this.make_dual_sections();
|
||||
if(this.dual_sections.length > 0) {
|
||||
this.render_object.render_results({
|
||||
sidelist: me.sidelist,
|
||||
sections: me.dual_sections,
|
||||
lists: me.lists
|
||||
}, me.keywords);
|
||||
}
|
||||
},
|
||||
|
||||
make_section: function(type, results) {
|
||||
var me = this;
|
||||
var results_column = $('<div class="col-sm-6 module-section-column">' +
|
||||
'<div class="h4 section-head">'+type+'</div>' +
|
||||
'<div class="section-body"></div>'+
|
||||
'</div>');
|
||||
results.slice(0, this.section_length).forEach(function(result) {
|
||||
results_column.append(me.make_result_item(type, result));
|
||||
});
|
||||
if(results.length > this.section_length) {
|
||||
results_column.append('<a class="small section-more" data-category="'
|
||||
+ type + '">More...</a>');
|
||||
}
|
||||
return results_column;
|
||||
}
|
||||
});
|
||||
|
||||
frappe.search.HelpSearch = frappe.search.GlobalSearch.extend({
|
||||
init: function() {
|
||||
this.search_type = 'Help';
|
||||
},
|
||||
|
||||
set_types: function() {
|
||||
this.types = [this.search_type];
|
||||
this.sidelist = this.make_sidelist();
|
||||
this.get_result_set(this.types[0]);
|
||||
},
|
||||
|
||||
make_sidelist: function() {
|
||||
var sidelist = $('<ul class="list-unstyled sidebar-menu nav-list"></ul>');
|
||||
var sidelist_item = '<li class="h6 list-link" data-search="'+ this.search_type + '"' +
|
||||
'data-category="'+ this.search_type + '"><a style="font-size: 11px;">'+
|
||||
this.search_type +'</a></li>';
|
||||
sidelist.append(sidelist_item);
|
||||
sidelist.append('<li class="divider"></li>');
|
||||
return sidelist;
|
||||
},
|
||||
|
||||
get_result_set: function(type) {
|
||||
var me = this;
|
||||
frappe.call({
|
||||
method: "frappe.utils.help.get_help",
|
||||
args: {
|
||||
text: me.keywords
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
// Help search doesn't have a more button for full list
|
||||
me.make_type_results(type, r.message, false);
|
||||
me.render_results();
|
||||
} else {
|
||||
me.render_object.render_next_search(me.keywords);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
make_type_results: function(type, results, more) {
|
||||
this.sections.push(this.make_section(type, results));
|
||||
this.lists[type] = this.make_full_list(type, results, more);
|
||||
},
|
||||
|
||||
make_result_item: function(type, result) {
|
||||
var me = this;
|
||||
var link_html = '<div class="result '+ type +'-result">' +
|
||||
'<a href="#" data-path="{0}" class="module-section-link small">{1}</a>' +
|
||||
'<p class="small">{2}</p>' +
|
||||
'</div>';
|
||||
var link = $(__(link_html, [result[2], result[0], result[1]]));
|
||||
link.find('a').on('click', frappe.help.show_results);
|
||||
return link;
|
||||
},
|
||||
|
||||
});
|
||||
7
frappe/public/js/frappe/ui/toolbar/search_header.html
Normal file
7
frappe/public/js/frappe/ui/toolbar/search_header.html
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<div class="input-group has-feedback search-header" style="margin:5px -5px;">
|
||||
<span class="input-group-addon">
|
||||
<i class="glyphicon glyphicon-search"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control search-input" placeholder="Search for...">
|
||||
<span class="input-group-addon"><a type="button" class="close" data-dismiss="modal" aria-hidden="true">×</a></span>
|
||||
</div>
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// MIT License. See license.txt
|
||||
|
||||
frappe.provide("frappe.ui.toolbar");
|
||||
frappe.provide('frappe.search');
|
||||
|
||||
frappe.ui.toolbar.Toolbar = Class.extend({
|
||||
init: function() {
|
||||
|
|
@ -11,6 +12,14 @@ frappe.ui.toolbar.Toolbar = Class.extend({
|
|||
|
||||
this.setup_sidebar();
|
||||
|
||||
this.awesome_bar = new frappe.search.AwesomeBar();
|
||||
this.awesome_bar.setup("#navbar-search");
|
||||
this.awesome_bar.setup("#modal-search");
|
||||
|
||||
this.search = new frappe.search.UnifiedSearch();
|
||||
this.help = new frappe.search.HelpSearch();
|
||||
this.search.setup();
|
||||
|
||||
$(document).on("notification-update", function() {
|
||||
frappe.ui.notifications.update_notifications();
|
||||
});
|
||||
|
|
@ -33,9 +42,6 @@ frappe.ui.toolbar.Toolbar = Class.extend({
|
|||
search_modal.find('#modal-search').focus();
|
||||
}, 300);
|
||||
});
|
||||
|
||||
frappe.search.setup("#navbar-search");
|
||||
frappe.search.setup("#modal-search");
|
||||
},
|
||||
|
||||
setup_sidebar: function () {
|
||||
|
|
@ -142,54 +148,28 @@ frappe.ui.toolbar.Toolbar = Class.extend({
|
|||
$('.dropdown-help .dropdown-menu').on('click', 'a', show_results);
|
||||
});
|
||||
|
||||
var $help_modal = frappe.get_modal("Help", "");
|
||||
$help_modal.addClass('help-modal');
|
||||
|
||||
var $result_modal = frappe.get_modal("", "");
|
||||
$result_modal.addClass("help-modal");
|
||||
|
||||
$(document).on("click", ".help-modal a", show_results);
|
||||
|
||||
var me = this;
|
||||
function show_help_results(keywords) {
|
||||
frappe.call({
|
||||
method: "frappe.utils.help.get_help",
|
||||
args: {
|
||||
text: keywords
|
||||
},
|
||||
callback: function (r) {
|
||||
var results = r.message || [];
|
||||
var result_html = "<h4 style='margin-bottom: 25px'>Showing results for '" + keywords + "' </h4>";
|
||||
|
||||
for (var i = 0, l = results.length; i < l; i++) {
|
||||
var title = results[i][0];
|
||||
var intro = results[i][1];
|
||||
var fpath = results[i][2];
|
||||
|
||||
result_html += "<div class='search-result'>" +
|
||||
"<a href='#' class='h4' data-path='"+fpath+"'>" + title + "</a>" +
|
||||
"<p>" + intro + "</p>" +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
if(results.length === 0) {
|
||||
result_html += "<p class='padding'>No results found</p>";
|
||||
}
|
||||
|
||||
$help_modal.find('.modal-body').html(result_html);
|
||||
$help_modal.modal('show');
|
||||
}
|
||||
});
|
||||
me.search.search_dialog.show();
|
||||
me.search.setup_search(keywords, [me.help]);
|
||||
}
|
||||
|
||||
frappe.provide('frappe.help');
|
||||
frappe.help.show_results = show_results;
|
||||
|
||||
function show_results(e) {
|
||||
//edit links
|
||||
href = e.target.href;
|
||||
if(href.indexOf('blob') > 0) {
|
||||
window.open(href, '_blank');
|
||||
}
|
||||
|
||||
var converter = new Showdown.converter();
|
||||
var path = $(this).attr("data-path");
|
||||
var path = $(e.target).attr("data-path");
|
||||
if(path) {
|
||||
e.preventDefault();
|
||||
frappe.call({
|
||||
|
|
@ -211,6 +191,7 @@ frappe.ui.toolbar.Toolbar = Class.extend({
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
$.extend(frappe.ui.toolbar, {
|
||||
add_dropdown_button: function(parent, label, click, icon) {
|
||||
var menu = frappe.ui.toolbar.get_menu(parent);
|
||||
|
|
|
|||
|
|
@ -527,10 +527,107 @@ textarea.form-control {
|
|||
.dropdown-menu {
|
||||
z-index: 100;
|
||||
max-height: 300px;
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.search-dialog {
|
||||
.modal-dialog {
|
||||
width: 768px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 0px 15px;
|
||||
}
|
||||
|
||||
input.form-control, .input-group-addon {
|
||||
border: none;
|
||||
border-left-style:none;
|
||||
}
|
||||
|
||||
input.form-control:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.input-group-addon{
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.layout-side-section,
|
||||
.layout-main-section {
|
||||
height: 500px;
|
||||
padding: 0px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.layout-side-section {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
// .results-area a {
|
||||
// color: #5E64FF;
|
||||
// }
|
||||
.module-section {
|
||||
.back-link {
|
||||
margin-bottom: 20px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.all-results-link:before {
|
||||
font-family: 'Octicons';
|
||||
content: '\f0a4';
|
||||
}
|
||||
}
|
||||
.dual-section .result a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.dual-section .result a b{
|
||||
color: #4e6161;
|
||||
}
|
||||
.result-status {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.more-results {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-xs) {
|
||||
.modal-dialog {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
height: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @screen-sm) {
|
||||
.module-body {
|
||||
margin: 0px;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.layout-side-section .sidebar-menu {
|
||||
margin: 30px 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result {
|
||||
p {
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.search-result {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.note-editor.note-frame .note-editing-area .note-editable {
|
||||
color: @text-color;
|
||||
}
|
||||
|
|
@ -582,4 +679,3 @@ textarea.form-control {
|
|||
|
||||
.c3-tooltip td.value {
|
||||
text-align: right; }
|
||||
|
||||
|
|
|
|||
|
|
@ -264,17 +264,12 @@ def make_test_records_for_doctype(doctype, verbose=0, force=False):
|
|||
print_mandatory_fields(doctype)
|
||||
|
||||
|
||||
def make_test_objects(doctype, test_records, verbose=None):
|
||||
def make_test_objects(doctype, test_records=None, verbose=None, reset=False):
|
||||
'''Make test objects from given list of `test_records` or from `test_records.json`'''
|
||||
records = []
|
||||
|
||||
# if not frappe.get_meta(doctype).issingle:
|
||||
# existing = frappe.get_all(doctype, filters={"name":("like", "_T-" + doctype + "-%")})
|
||||
# if existing:
|
||||
# return [d.name for d in existing]
|
||||
#
|
||||
# existing = frappe.get_all(doctype, filters={"name":("like", "_Test " + doctype + "%")})
|
||||
# if existing:
|
||||
# return [d.name for d in existing]
|
||||
if test_records is None:
|
||||
test_records = frappe.get_test_records(doctype)
|
||||
|
||||
for doc in test_records:
|
||||
if not doc.get("doctype"):
|
||||
|
|
@ -285,7 +280,7 @@ def make_test_objects(doctype, test_records, verbose=None):
|
|||
if doc.get('name'):
|
||||
d.name = doc.get('name')
|
||||
|
||||
if frappe.local.test_objects.get(d.doctype):
|
||||
if frappe.local.test_objects.get(d.doctype) and not reset:
|
||||
# do not create test records, if already exists
|
||||
return []
|
||||
|
||||
|
|
|
|||
117
frappe/tests/test_global_search.py
Normal file
117
frappe/tests/test_global_search.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import frappe
|
||||
|
||||
from frappe.utils import global_search
|
||||
from frappe.test_runner import make_test_objects
|
||||
import frappe.utils
|
||||
|
||||
class TestGlobalSearch(unittest.TestCase):
|
||||
def setUp(self):
|
||||
global_search.setup_global_search_table()
|
||||
self.assertTrue('__global_search' in frappe.db.get_tables())
|
||||
doctype = "Event"
|
||||
global_search.reset()
|
||||
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||
make_property_setter(doctype, "subject", "in_global_search", 1, "Int")
|
||||
make_property_setter(doctype, "event_type", "in_global_search", 1, "Int")
|
||||
make_property_setter(doctype, "roles", "in_global_search", 1, "Int")
|
||||
make_property_setter(doctype, "repeat_on", "in_global_search", 0, "Int")
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.sql('delete from `tabProperty Setter` where doc_type="Event"')
|
||||
frappe.clear_cache(doctype='Event')
|
||||
frappe.db.sql('delete from `tabEvent`')
|
||||
frappe.db.sql('delete from `tabEvent Role`')
|
||||
frappe.db.sql('delete from __global_search')
|
||||
make_test_objects('Event')
|
||||
frappe.db.commit()
|
||||
|
||||
def insert_test_events(self):
|
||||
frappe.db.sql('delete from tabEvent')
|
||||
phrases = ['"The Sixth Extinction II: Amor Fati" is the second episode of the seventh season of the American science fiction.',
|
||||
'After Mulder awakens from his coma, he realizes his duty to prevent alien colonization. ',
|
||||
'Carter explored themes of extraterrestrial involvement in ancient mass extinctions in this episode, the third in a trilogy.']
|
||||
|
||||
for text in phrases:
|
||||
frappe.get_doc(dict(
|
||||
doctype='Event',
|
||||
subject=text,
|
||||
repeat_on='Every Month',
|
||||
starts_on=frappe.utils.now_datetime())).insert()
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
def test_search(self):
|
||||
self.insert_test_events()
|
||||
results = global_search.search('awakens')
|
||||
self.assertTrue('After Mulder awakens from his coma, he realizes his duty to prevent alien colonization. ' in results[0].content)
|
||||
|
||||
results = global_search.search('extraterrestrial')
|
||||
self.assertTrue('Carter explored themes of extraterrestrial involvement in ancient mass extinctions in this episode, the third in a trilogy.' in results[0].content)
|
||||
|
||||
def test_update_doc(self):
|
||||
self.insert_test_events()
|
||||
test_subject = 'testing global search'
|
||||
event = frappe.get_doc('Event', frappe.get_all('Event')[0].name)
|
||||
event.subject = test_subject
|
||||
event.save()
|
||||
frappe.db.commit()
|
||||
|
||||
results = global_search.search('testing global search')
|
||||
|
||||
self.assertTrue('testing global search' in results[0].content)
|
||||
|
||||
def test_update_fields(self):
|
||||
self.insert_test_events()
|
||||
results = global_search.search('Every Month')
|
||||
self.assertEquals(len(results), 0)
|
||||
doctype = "Event"
|
||||
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||
make_property_setter(doctype, "repeat_on", "in_global_search", 1, "Int")
|
||||
global_search.rebuild_for_doctype(doctype)
|
||||
results = global_search.search('Every Month')
|
||||
self.assertEquals(len(results), 3)
|
||||
|
||||
def test_delete_doc(self):
|
||||
self.insert_test_events()
|
||||
|
||||
event_name = frappe.get_all('Event')[0].name
|
||||
event = frappe.get_doc('Event', event_name)
|
||||
test_subject = event.subject
|
||||
results = global_search.search(test_subject)
|
||||
self.assertEquals(len(results), 1)
|
||||
|
||||
frappe.delete_doc('Event', event_name)
|
||||
|
||||
results = global_search.search(test_subject)
|
||||
self.assertEquals(len(results), 0)
|
||||
|
||||
def test_insert_child_table(self):
|
||||
frappe.db.sql('delete from tabEvent')
|
||||
frappe.db.sql('delete from `tabEvent Role`')
|
||||
phrases = ['Hydrus is a small constellation in the deep southern sky. ',
|
||||
'It was first depicted on a celestial atlas by Johann Bayer in his 1603 Uranometria. ',
|
||||
'The French explorer and astronomer Nicolas Louis de Lacaille charted the brighter stars and gave their Bayer designations in 1756. ',
|
||||
'Its name means "male water snake", as opposed to Hydra, a much larger constellation that represents a female water snake. ',
|
||||
'It remains below the horizon for most Northern Hemisphere observers.',
|
||||
'The brightest star is the 2.8-magnitude Beta Hydri, also the closest reasonably bright star to the south celestial pole. ',
|
||||
'Pulsating between magnitude 3.26 and 3.33, Gamma Hydri is a variable red giant some 60 times the diameter of our Sun. ',
|
||||
'Lying near it is VW Hydri, one of the brightest dwarf novae in the heavens. ',
|
||||
'Four star systems have been found to have exoplanets to date, most notably HD 10180, which could bear up to nine planetary companions.']
|
||||
|
||||
for text in phrases:
|
||||
doc = frappe.get_doc({
|
||||
'doctype':'Event',
|
||||
'subject': text,
|
||||
'starts_on': frappe.utils.now_datetime()
|
||||
})
|
||||
doc.append('roles', dict(role='Administrator'))
|
||||
doc.insert()
|
||||
|
||||
frappe.db.commit()
|
||||
results = global_search.search('Administrator')
|
||||
self.assertEquals(len(results), 9)
|
||||
|
|
@ -25,6 +25,7 @@ def enqueue(method, queue='default', timeout=300, event=None,
|
|||
:param event: this is passed to enable clearing of jobs from queues
|
||||
:param async: if async=False, the method is executed immediately, else via a worker
|
||||
:param job_name: can be used to name an enqueue call, which can be used to prevent duplicate calls
|
||||
:param now: if now=True, the method is executed via frappe.call
|
||||
:param kwargs: keyword arguments to be passed to the method
|
||||
'''
|
||||
if now:
|
||||
|
|
|
|||
151
frappe/utils/global_search.py
Normal file
151
frappe/utils/global_search.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
def setup_global_search_table():
|
||||
'''Creates __global_seach table'''
|
||||
if not '__global_search' in frappe.db.get_tables():
|
||||
frappe.db.sql('''create table __global_search(
|
||||
doctype varchar(100),
|
||||
name varchar(140),
|
||||
content text,
|
||||
fulltext(content),
|
||||
unique (doctype, name))
|
||||
COLLATE=utf8mb4_unicode_ci
|
||||
ENGINE=MyISAM
|
||||
CHARACTER SET=utf8mb4''')
|
||||
|
||||
def reset():
|
||||
'''Deletes all data in __global_search'''
|
||||
frappe.db.sql('delete from __global_search')
|
||||
|
||||
def update_global_search(doc):
|
||||
'''Add values marked with `in_global_search` to
|
||||
`frappe.flags.update_global_search` from given doc
|
||||
:param doc: Document to be added to global search'''
|
||||
|
||||
if frappe.flags.update_global_search==None:
|
||||
frappe.flags.update_global_search = []
|
||||
|
||||
content = []
|
||||
for field in doc.meta.get_global_search_fields():
|
||||
if doc.get(field.fieldname):
|
||||
if getattr(field, 'fieldtype', None) == "Table":
|
||||
|
||||
# Get children
|
||||
for d in doc.get(field.fieldname):
|
||||
if d.parent == doc.name:
|
||||
|
||||
for field in d.meta.fields:
|
||||
if d.get(field.fieldname):
|
||||
content.append(field.label + ": " + unicode(d.get(field.fieldname)))
|
||||
else:
|
||||
content.append(field.label + ": " + unicode(doc.get(field.fieldname)))
|
||||
|
||||
if content:
|
||||
frappe.flags.update_global_search.append(
|
||||
dict(doctype=doc.doctype, name=doc.name, content='|||'.join(content)))
|
||||
|
||||
def sync_global_search():
|
||||
'''Add values from `frappe.flags.update_global_search` to __global_search.
|
||||
This is called internally at the end of the request.'''
|
||||
|
||||
for value in frappe.flags.update_global_search:
|
||||
frappe.db.sql('''
|
||||
insert into __global_search
|
||||
(doctype, name, content)
|
||||
values
|
||||
(%(doctype)s, %(name)s, %(content)s)
|
||||
on duplicate key update
|
||||
content = %(content)s''', value)
|
||||
|
||||
frappe.flags.update_global_search = []
|
||||
|
||||
def rebuild_for_doctype(doctype):
|
||||
'''Rebuild entries of doctype's documents in __global_search on change of
|
||||
searchable fields
|
||||
:param doctype: Doctype '''
|
||||
|
||||
frappe.db.sql('''
|
||||
delete
|
||||
from __global_search
|
||||
where
|
||||
doctype = (%s)''', doctype, as_dict=True)
|
||||
|
||||
for d in frappe.get_all(doctype):
|
||||
update_global_search(frappe.get_doc(doctype, d.name))
|
||||
sync_global_search()
|
||||
|
||||
def delete_for_document(doc):
|
||||
'''Delete the __global_search entry of a document that has
|
||||
been deleted
|
||||
:param doc: Deleted document'''
|
||||
|
||||
frappe.db.sql('''
|
||||
delete
|
||||
from __global_search
|
||||
where
|
||||
name = (%s)''', (doc.name), as_dict=True)
|
||||
|
||||
@frappe.whitelist()
|
||||
def search(text, start=0, limit=20):
|
||||
'''Search for given text in __global_search
|
||||
:param text: phrase to be searched
|
||||
:param start: start results at, default 0
|
||||
:param limit: number of results to return, default 20
|
||||
:return: Array of result objects'''
|
||||
|
||||
text = "+" + text + "*"
|
||||
results = frappe.db.sql('''
|
||||
select
|
||||
doctype, name, content
|
||||
from
|
||||
__global_search
|
||||
where
|
||||
match(content) against (%s IN BOOLEAN MODE)
|
||||
limit {start}, {limit}'''.format(start=start, limit=limit), text, as_dict=True)
|
||||
return results
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_search_doctypes(text):
|
||||
'''Search for all t
|
||||
:param text: phrase to be searched
|
||||
:return: Array of result objects'''
|
||||
|
||||
text = "+" + text + "*"
|
||||
results = frappe.db.sql('''
|
||||
select
|
||||
doctype
|
||||
from
|
||||
__global_search
|
||||
where
|
||||
match(content) against (%s IN BOOLEAN MODE)
|
||||
group by
|
||||
doctype
|
||||
order by
|
||||
count(doctype) desc limit 0, 80''', text, as_dict=True)
|
||||
return results
|
||||
|
||||
@frappe.whitelist()
|
||||
def search_in_doctype(doctype, text, start, limit):
|
||||
'''Search for given text in given doctype in __global_search
|
||||
:param doctype: doctype to be searched in
|
||||
:param text: phrase to be searched
|
||||
:param start: start results at, default 0
|
||||
:param limit: number of results to return, default 20
|
||||
:return: Array of result objects'''
|
||||
|
||||
text = "+" + text + "*"
|
||||
results = frappe.db.sql('''
|
||||
select
|
||||
doctype, name, content
|
||||
from
|
||||
__global_search
|
||||
where
|
||||
doctype = %s AND
|
||||
match(content) against (%s IN BOOLEAN MODE)
|
||||
limit {start}, {limit}'''.format(start=start, limit=limit), (doctype, text), as_dict=True)
|
||||
return results
|
||||
|
|
@ -82,8 +82,8 @@ class HelpDatabase(object):
|
|||
def search(self, words):
|
||||
self.connect()
|
||||
return self.db.sql('''
|
||||
select title, intro, path from help where title like '%{term}%' union
|
||||
select title, intro, path from help where match(content) against ('{term}') limit 10'''.format(term=words))
|
||||
select title, intro, path from help where title like %s union
|
||||
select title, intro, path from help where match(content) against (%s) limit 10''', ('%'+words+'%', words))
|
||||
|
||||
def get_content(self, path):
|
||||
self.connect()
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ def after_install():
|
|||
update_password("Administrator", get_admin_password())
|
||||
|
||||
# setup wizard now in frappe
|
||||
frappe.db.set_default('desktop:home_page', 'setup-wizard');
|
||||
frappe.db.set_default('desktop:home_page', 'setup-wizard')
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// MIT License. See license.txt
|
||||
|
||||
frappe.provide("website");
|
||||
frappe.provide("frappe.search_path");
|
||||
frappe.provide("frappe.awesome_bar_path");
|
||||
cur_frm = null;
|
||||
|
||||
$.extend(frappe, {
|
||||
|
|
@ -303,13 +303,13 @@ $.extend(frappe, {
|
|||
});
|
||||
},
|
||||
do_search: function(val) {
|
||||
var path = (frappe.search_path && frappe.search_path[location.pathname]
|
||||
var path = (frappe.awesome_bar_path && frappe.awesome_bar_path[location.pathname]
|
||||
|| window.search_path || location.pathname);
|
||||
|
||||
window.location.href = path + "?txt=" + encodeURIComponent(val);
|
||||
},
|
||||
set_search_path: function(path) {
|
||||
frappe.search_path[location.pathname] = path;
|
||||
frappe.awesome_bar_path[location.pathname] = path;
|
||||
},
|
||||
make_navbar_active: function() {
|
||||
var pathname = window.location.pathname;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue