* [refactor] domain and domain settings * [fix] test_domain.py * [fix] patches * [fix] domain activation after setup * [fix] tests and lint * [fix] tests and lint * [enhance] better prompt naming * [fix] setup wizard test * [fix] testing * [minor] new item in quick entry from form dashboardversion-14
@@ -475,13 +475,26 @@ def only_for(roles): | |||
if not roles.intersection(myroles): | |||
raise PermissionError | |||
def get_domain_data(module): | |||
try: | |||
domain_data = get_hooks('domains') | |||
if module in domain_data: | |||
return _dict(get_attr(get_hooks('domains')[module][0] + '.data')) | |||
else: | |||
return _dict() | |||
except ImportError: | |||
if local.flags.in_test: | |||
return _dict() | |||
else: | |||
raise | |||
def clear_cache(user=None, doctype=None): | |||
"""Clear **User**, **DocType** or global cache. | |||
:param user: If user is given, only user cache is cleared. | |||
:param doctype: If doctype is given, only DocType cache is cleared.""" | |||
import frappe.sessions | |||
from frappe.core.doctype.domain_settings.domain_settings import clear_domain_cache | |||
if doctype: | |||
import frappe.model.meta | |||
frappe.model.meta.clear_cache(doctype) | |||
@@ -493,7 +506,6 @@ def clear_cache(user=None, doctype=None): | |||
frappe.sessions.clear_cache() | |||
translate.clear_cache() | |||
reset_metadata_version() | |||
clear_domain_cache() | |||
local.cache = {} | |||
local.new_doc_templates = {} | |||
@@ -60,11 +60,11 @@ function watch() { | |||
io.emit('reload_css', filename); | |||
} | |||
}); | |||
watch_js(function (filename) { | |||
if(socket_connection) { | |||
io.emit('reload_js', filename); | |||
} | |||
}); | |||
// watch_js(function (filename) { | |||
// if(socket_connection) { | |||
// io.emit('reload_js', filename); | |||
// } | |||
// }); | |||
watch_build_json(); | |||
}); | |||
@@ -4,7 +4,89 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields | |||
class Domain(Document): | |||
pass | |||
'''Domain documents are created automatically when DocTypes | |||
with "Restricted" domains are imported during | |||
installation or migration''' | |||
def setup_domain(self): | |||
'''Setup domain icons, permissions, custom fields etc.''' | |||
self.setup_data() | |||
self.setup_roles() | |||
self.setup_properties() | |||
self.set_values() | |||
if not int(frappe.db.get_single_value('System Settings', 'setup_complete') or 0): | |||
# if setup not complete, setup desktop etc. | |||
self.setup_sidebar_items() | |||
self.setup_desktop_icons() | |||
self.set_default_portal_role() | |||
if self.data.custom_fields: | |||
create_custom_fields(self.data.custom_fields) | |||
if self.data.on_setup: | |||
# custom on_setup method | |||
frappe.get_attr(self.data.on_setup)() | |||
def setup_roles(self): | |||
'''Enable roles that are restricted to this domain''' | |||
if self.data.restricted_roles: | |||
for role_name in self.data.restricted_roles: | |||
role = frappe.get_doc('Role', role_name) | |||
role.disabled = 0 | |||
role.save() | |||
def setup_data(self, domain=None): | |||
'''Load domain info via hooks''' | |||
self.data = frappe.get_domain_data(self.name) | |||
def get_domain_data(self, module): | |||
return frappe.get_attr(frappe.get_hooks('domains')[self.name] + '.data') | |||
def set_default_portal_role(self): | |||
'''Set default portal role based on domain''' | |||
if self.data.get('default_portal_role'): | |||
frappe.db.set_value('Portal Settings', None, 'default_role', | |||
self.data.get('default_portal_role')) | |||
def setup_desktop_icons(self): | |||
'''set desktop icons form `data.desktop_icons`''' | |||
from frappe.desk.doctype.desktop_icon.desktop_icon import set_desktop_icons | |||
if self.data.desktop_icons: | |||
set_desktop_icons(self.data.desktop_icons) | |||
def setup_properties(self): | |||
if self.data.properties: | |||
for args in self.data.properties: | |||
frappe.make_property_setter(args) | |||
def set_values(self): | |||
'''set values based on `data.set_value`''' | |||
if self.data.set_value: | |||
for args in self.data.set_value: | |||
doc = frappe.get_doc(args[0], args[1] or args[0]) | |||
doc.set(args[2], args[3]) | |||
doc.save() | |||
def setup_sidebar_items(self): | |||
'''Enable / disable sidebar items''' | |||
if self.data.allow_sidebar_items: | |||
# disable all | |||
frappe.db.sql('update `tabPortal Menu Item` set enabled=0') | |||
# enable | |||
frappe.db.sql('''update `tabPortal Menu Item` set enabled=1 | |||
where route in ({0})'''.format(', '.join(['"{0}"'.format(d) for d in self.data.allow_sidebar_items]))) | |||
if self.data.remove_sidebar_items: | |||
# disable all | |||
frappe.db.sql('update `tabPortal Menu Item` set enabled=1') | |||
# enable | |||
frappe.db.sql('''update `tabPortal Menu Item` set enabled=0 | |||
where route in ({0})'''.format(', '.join(['"{0}"'.format(d) for d in self.data.remove_sidebar_items]))) |
@@ -7,8 +7,46 @@ import frappe | |||
from frappe.model.document import Document | |||
class DomainSettings(Document): | |||
def set_active_domains(self, domains): | |||
self.active_domains = [] | |||
for d in domains: | |||
self.append('active_domains', dict(domain=d)) | |||
self.save() | |||
def on_update(self): | |||
clear_domain_cache() | |||
for d in self.active_domains: | |||
domain = frappe.get_doc('Domain', d.domain) | |||
domain.setup_domain() | |||
self.restrict_roles_and_modules() | |||
frappe.clear_cache() | |||
def restrict_roles_and_modules(self): | |||
'''Disable all restricted roles and set `restrict_to_domain` property in Module Def''' | |||
active_domains = frappe.get_active_domains() | |||
all_domains = (frappe.get_hooks('domains') or {}).keys() | |||
def remove_role(role): | |||
frappe.db.sql('delete from `tabHas Role` where role=%s', role) | |||
frappe.set_value('Role', role, 'disabled', 1) | |||
for domain in all_domains: | |||
data = frappe.get_domain_data(domain) | |||
if not frappe.db.get_value('Domain', domain): | |||
frappe.get_doc(dict(doctype='Domain', domain=domain)).insert() | |||
if 'modules' in data: | |||
for module in data.get('modules'): | |||
frappe.db.set_value('Module Def', module, 'restrict_to_domain', domain) | |||
if 'restricted_roles' in data: | |||
for role in data['restricted_roles']: | |||
if not frappe.db.get_value('Role', role): | |||
frappe.get_doc(dict(doctype='Role', role_name=role)).insert() | |||
frappe.db.set_value('Role', role, 'restrict_to_domain', domain) | |||
if domain not in active_domains: | |||
remove_role(role) | |||
def get_active_domains(): | |||
""" get the domains set in the Domain Settings as active domain """ | |||
@@ -33,6 +71,3 @@ def get_active_modules(): | |||
return active_modules | |||
return frappe.cache().get_value('active_modules', _get_active_modules) | |||
def clear_domain_cache(): | |||
frappe.cache().delete_key(['active_domains', 'active_modules']) |
@@ -14,7 +14,7 @@ from frappe.twofactor import toggle_two_factor_auth | |||
class SystemSettings(Document): | |||
def validate(self): | |||
enable_password_policy = cint(self.enable_password_policy) and True or False | |||
minimum_password_score = cint(self.minimum_password_score) or 0 | |||
minimum_password_score = cint(getattr(self, 'minimum_password_score', 0)) or 0 | |||
if enable_password_policy and minimum_password_score <= 0: | |||
frappe.throw(_("Please select Minimum Password Score")) | |||
elif not enable_password_policy: | |||
@@ -111,6 +111,10 @@ def create_custom_fields(custom_fields): | |||
:param custom_fields: example `{'Sales Invoice': [dict(fieldname='test')]}`''' | |||
for doctype, fields in custom_fields.items(): | |||
if isinstance(fields, dict): | |||
# only one field | |||
fields = [fields] | |||
for df in fields: | |||
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df["fieldname"]}) | |||
if not field: | |||
@@ -508,19 +508,22 @@ frappe.setup.utils = { | |||
bind_language_events: function(slide) { | |||
slide.get_input("language").unbind("change").on("change", function() { | |||
var lang = $(this).val() || "English"; | |||
frappe._messages = {}; | |||
frappe.call({ | |||
method: "frappe.desk.page.setup_wizard.setup_wizard.load_messages", | |||
freeze: true, | |||
args: { | |||
language: lang | |||
}, | |||
callback: function(r) { | |||
frappe.setup._from_load_messages = true; | |||
frappe.wizard.refresh_slides(); | |||
} | |||
}); | |||
clearTimeout (slide.language_call_timeout); | |||
slide.language_call_timeout = setTimeout (() => { | |||
var lang = $(this).val() || "English"; | |||
frappe._messages = {}; | |||
frappe.call({ | |||
method: "frappe.desk.page.setup_wizard.setup_wizard.load_messages", | |||
freeze: true, | |||
args: { | |||
language: lang | |||
}, | |||
callback: function(r) { | |||
frappe.setup._from_load_messages = true; | |||
frappe.wizard.refresh_slides(); | |||
} | |||
}); | |||
}, 500); | |||
}); | |||
}, | |||
@@ -352,7 +352,7 @@ def get_filters_cond(doctype, filters, conditions, ignore_permissions=None, with | |||
for f in filters: | |||
if isinstance(f[1], string_types) and f[1][0] == '!': | |||
flt.append([doctype, f[0], '!=', f[1][1:]]) | |||
elif isinstance(f[1], list) and \ | |||
elif isinstance(f[1], (list, tuple)) and \ | |||
f[1][0] in (">", "<", ">=", "<=", "like", "not like", "in", "not in", "between"): | |||
flt.append([doctype, f[0], f[1][0], f[1][1]]) | |||
@@ -7,10 +7,11 @@ frappe.patches.v7_1.rename_scheduler_log_to_error_log | |||
frappe.patches.v6_1.rename_file_data | |||
frappe.patches.v7_0.re_route #2016-06-27 | |||
frappe.patches.v7_2.remove_in_filter | |||
execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2017-03-09 | |||
frappe.patches.v8_0.drop_in_dialog | |||
frappe.patches.v8_0.drop_in_dialog #2017-09-22 | |||
execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2017-09-22 | |||
execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2017-03-03 | |||
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2017-03-03 | |||
execute:frappe.reload_doc('core', 'doctype', 'module_def') #2017-09-22 | |||
frappe.patches.v8_0.drop_is_custom_from_docperm | |||
frappe.patches.v8_0.update_records_in_global_search #11-05-2017 | |||
frappe.patches.v8_0.update_published_in_global_search | |||
@@ -2,6 +2,13 @@ | |||
// MIT License. See license.txt | |||
frappe.db = { | |||
exists: function(doctype, name) { | |||
return new Promise ((resolve) => { | |||
frappe.db.get_value(doctype, {name: name}, 'name').then((r) => { | |||
(r.message && r.message.name) ? resolve(true) : resolve(false); | |||
}); | |||
}); | |||
}, | |||
get_value: function(doctype, filters, fieldname, callback) { | |||
return frappe.call({ | |||
method: "frappe.client.get_value", | |||
@@ -47,6 +47,10 @@ frappe.ui.form.Control = Class.extend({ | |||
// returns "Read", "Write" or "None" | |||
// as strings based on permissions | |||
get_status: function(explain) { | |||
if (this.df.get_status) { | |||
return this.df.get_status(this); | |||
} | |||
if(!this.doctype && !this.docname) { | |||
// like in case of a dialog box | |||
if (cint(this.df.hidden)) { | |||
@@ -71,7 +71,7 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({ | |||
} | |||
}; | |||
if(me.disp_status != "None") { | |||
if (me.disp_status != "None") { | |||
// refresh value | |||
if(me.doctype && me.docname) { | |||
me.value = frappe.model.get_value(me.doctype, me.docname, me.df.fieldname); | |||
@@ -28,9 +28,9 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({ | |||
setup_autoname_check: function() { | |||
if (!this.df.parent) return; | |||
this.meta = frappe.get_meta(this.df.parent); | |||
if (this.meta && this.meta.autoname | |||
if (this.meta && ((this.meta.autoname | |||
&& this.meta.autoname.substr(0, 6)==='field:' | |||
&& this.meta.autoname.substr(6) === this.df.fieldname) { | |||
&& this.meta.autoname.substr(6) === this.df.fieldname) || this.df.fieldname==='__newname') ) { | |||
this.$input.on('keyup', () => { | |||
this.set_description(''); | |||
if (this.doc && this.doc.__islocal) { | |||
@@ -12,13 +12,11 @@ frappe.ui.form.ControlPassword = frappe.ui.form.ControlData.extend({ | |||
this.indicator = this.$wrapper.find('.password-strength-indicator'); | |||
this.message = this.$wrapper.find('.help-box'); | |||
this.$input.on('input', () => { | |||
var $this = $(this); | |||
clearTimeout($this.data('timeout')); | |||
$this.data('timeout', setTimeout(() => { | |||
var txt = me.$input.val(); | |||
me.get_password_strength(txt); | |||
}), 300); | |||
this.$input.on('keyup', () => { | |||
clearTimeout(this.check_password_timeout); | |||
this.check_password_timeout = setTimeout (() => { | |||
me.get_password_strength(me.$input.val()); | |||
}, 500); | |||
}); | |||
}, | |||
get_password_strength: function(value) { | |||
@@ -25,7 +25,7 @@ frappe.ui.form.Layout = Class.extend({ | |||
this.wrapper = $('<div class="form-layout">').appendTo(this.parent); | |||
this.message = $('<div class="form-message text-muted small hidden"></div>').appendTo(this.wrapper); | |||
if(!this.fields) { | |||
this.fields = frappe.meta.sort_docfields(frappe.meta.docfield_map[this.doctype]); | |||
this.fields = this.get_doctype_fields(); | |||
} | |||
this.setup_tabbing(); | |||
this.render(); | |||
@@ -35,6 +35,28 @@ frappe.ui.form.Layout = Class.extend({ | |||
this.show_message(__("This form does not have any input")); | |||
} | |||
}, | |||
get_doctype_fields: function() { | |||
let fields = [ | |||
{ | |||
parent: this.frm.doctype, | |||
fieldtype: 'Data', | |||
fieldname: '__newname', | |||
reqd: 1, | |||
hidden: 1, | |||
label: __('Name'), | |||
get_status: function(field) { | |||
if (field.frm && field.frm.is_new() | |||
&& field.frm.meta.autoname | |||
&& ['prompt', 'name'].includes(field.frm.meta.autoname.toLowerCase())) { | |||
return 'Write'; | |||
} | |||
return 'None'; | |||
} | |||
} | |||
]; | |||
fields = fields.concat(frappe.meta.sort_docfields(frappe.meta.docfield_map[this.doctype])); | |||
return fields; | |||
}, | |||
show_message: function(html) { | |||
if(html) { | |||
if(html.substr(0, 1)!=='<') { | |||
@@ -1,6 +1,6 @@ | |||
frappe.provide('frappe.ui.form'); | |||
frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback) => { | |||
frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback, doc) => { | |||
var trimmed_doctype = doctype.replace(/ /g, ''); | |||
var controller_name = "QuickEntryForm"; | |||
@@ -8,15 +8,16 @@ frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback) => { | |||
controller_name = trimmed_doctype + "QuickEntryForm"; | |||
} | |||
frappe.quick_entry = new frappe.ui.form[controller_name](doctype, after_insert, init_callback); | |||
frappe.quick_entry = new frappe.ui.form[controller_name](doctype, after_insert, init_callback, doc); | |||
return frappe.quick_entry.setup(); | |||
}; | |||
frappe.ui.form.QuickEntryForm = Class.extend({ | |||
init: function(doctype, after_insert, init_callback){ | |||
init: function(doctype, after_insert, init_callback, doc) { | |||
this.doctype = doctype; | |||
this.after_insert = after_insert; | |||
this.init_callback = init_callback; | |||
this.doc = doc; | |||
}, | |||
setup: function() { | |||
@@ -40,7 +41,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({ | |||
this.mandatory = $.map(frappe.get_meta(this.doctype).fields, | |||
function(d) { return (d.reqd || d.bold && !d.read_only) ? d : null; }); | |||
this.meta = frappe.get_meta(this.doctype); | |||
this.doc = frappe.model.get_new_doc(this.doctype, null, null, true); | |||
if (!this.doc) { | |||
this.doc = frappe.model.get_new_doc(this.doctype, null, null, true); | |||
} | |||
}, | |||
is_quick_entry: function(){ | |||
@@ -108,7 +111,7 @@ frappe.ui.form.QuickEntryForm = Class.extend({ | |||
this.dialog.onhide = () => frappe.quick_entry = null; | |||
this.dialog.show(); | |||
this.set_defaults(); | |||
if (this.init_callback) { | |||
this.init_callback(this.dialog); | |||
} | |||
@@ -19,27 +19,24 @@ frappe.ui.form.save = function (frm, action, callback, btn) { | |||
var save = function () { | |||
remove_empty_rows(); | |||
check_name(function () { | |||
$(frm.wrapper).addClass('validated-form'); | |||
if (check_mandatory()) { | |||
_call({ | |||
method: "frappe.desk.form.save.savedocs", | |||
args: { doc: frm.doc, action: action }, | |||
callback: function (r) { | |||
$(document).trigger("save", [frm.doc]); | |||
callback(r); | |||
}, | |||
error: function (r) { | |||
callback(r); | |||
}, | |||
btn: btn, | |||
freeze_message: freeze_message | |||
}); | |||
} else { | |||
$(btn).prop("disabled", false); | |||
} | |||
}); | |||
$(frm.wrapper).addClass('validated-form'); | |||
if (check_mandatory()) { | |||
_call({ | |||
method: "frappe.desk.form.save.savedocs", | |||
args: { doc: frm.doc, action: action }, | |||
callback: function (r) { | |||
$(document).trigger("save", [frm.doc]); | |||
callback(r); | |||
}, | |||
error: function (r) { | |||
callback(r); | |||
}, | |||
btn: btn, | |||
freeze_message: freeze_message | |||
}); | |||
} else { | |||
$(btn).prop("disabled", false); | |||
} | |||
}; | |||
var remove_empty_rows = function() { | |||
@@ -107,36 +104,6 @@ frappe.ui.form.save = function (frm, action, callback, btn) { | |||
}); | |||
}; | |||
var check_name = function (callback) { | |||
var doc = frm.doc; | |||
var meta = locals.DocType[doc.doctype]; | |||
if (doc.__islocal && (meta && meta.autoname | |||
&& meta.autoname.toLowerCase() == 'prompt')) { | |||
var d = frappe.prompt(__("Name"), function (values) { | |||
var newname = values.value; | |||
if (newname) { | |||
doc.__newname = strip(newname); | |||
} else { | |||
frappe.msgprint(__("Name is required")); | |||
throw "name required"; | |||
} | |||
callback(); | |||
}, __('Enter the name of the new {0}', [doc.doctype]), __("Create")); | |||
if (doc.__newname) { | |||
d.set_value("value", doc.__newname); | |||
} | |||
d.onhide = function () { | |||
$(btn).prop("disabled", false); | |||
} | |||
} else { | |||
callback(); | |||
} | |||
}; | |||
var check_mandatory = function () { | |||
var me = this; | |||
var has_errors = false; | |||
@@ -50,6 +50,15 @@ frappe.avatar = function(user, css_class, title) { | |||
} | |||
} | |||
frappe.ui.scroll = function(element, animate, additional_offset) { | |||
var header_offset = $(".navbar").height() + $(".page-head").height(); | |||
var top = $(element).offset().top - header_offset - cint(additional_offset); | |||
if (animate) { | |||
$("html, body").animate({ scrollTop: top }); | |||
} else { | |||
$(window).scrollTop(top); | |||
} | |||
}; | |||
frappe.get_palette = function(txt) { | |||
return '#fafbfc'; | |||
@@ -327,17 +327,23 @@ $.extend(frappe.model, { | |||
set_value: function(doctype, docname, fieldname, value, fieldtype) { | |||
/* help: Set a value locally (if changed) and execute triggers */ | |||
var doc = locals[doctype] && locals[doctype][docname]; | |||
var doc; | |||
if ($.isPlainObject(doctype)) { | |||
// first parameter is the doc, shift parameters to the left | |||
doc = doctype; fieldname = docname; value = fieldname; | |||
} else { | |||
doc = locals[doctype] && locals[doctype][docname]; | |||
} | |||
var to_update = fieldname; | |||
let to_update = fieldname; | |||
let tasks = []; | |||
if(!$.isPlainObject(to_update)) { | |||
to_update = {}; | |||
to_update[fieldname] = value; | |||
} | |||
$.each(to_update, function(key, value) { | |||
if(doc && doc[key] !== value) { | |||
$.each(to_update, (key, value) => { | |||
if (doc && doc[key] !== value) { | |||
if(doc.__unedited && !(!doc[key] && !value)) { | |||
// unset unedited flag for virgin rows | |||
doc.__unedited = false; | |||
@@ -145,6 +145,7 @@ frappe.request.call = function(opts) { | |||
frappe.msgprint({message:__("Server Error: Please check your server logs or contact tech support."), title:__('Something went wrong'), indicator: 'red'}); | |||
try { | |||
opts.error_callback && opts.error_callback(); | |||
frappe.request.report_error(xhr, opts); | |||
} catch (e) { | |||
frappe.request.report_error(xhr, opts); | |||
} | |||
@@ -222,17 +222,19 @@ frappe.socketio = { | |||
}, 5); | |||
}); | |||
// js files show alert | |||
frappe.socketio.file_watcher.on('reload_js', function(filename) { | |||
filename = "assets/" + filename; | |||
var msg = $(` | |||
<span>${filename} changed <a data-action="reload">Click to Reload</a></span> | |||
`) | |||
msg.find('a').click(frappe.ui.toolbar.clear_cache); | |||
frappe.show_alert({ | |||
indicator: 'orange', | |||
message: msg | |||
}, 5); | |||
}); | |||
// commenting as this kills a branch change | |||
// frappe.socketio.file_watcher.on('reload_js', function(filename) { | |||
// filename = "assets/" + filename; | |||
// var msg = $(` | |||
// <span>${filename} changed <a data-action="reload">Click to Reload</a></span> | |||
// `) | |||
// msg.find('a').click(frappe.ui.toolbar.clear_cache); | |||
// frappe.show_alert({ | |||
// indicator: 'orange', | |||
// message: msg | |||
// }, 5); | |||
// }); | |||
}, | |||
process_response: function(data, method) { | |||
if(!data) { | |||
@@ -495,14 +495,4 @@ frappe.ui.Page = Class.extend({ | |||
this.wrapper.trigger('view-change'); | |||
}, | |||
}); | |||
frappe.ui.scroll = function(element, animate, additional_offset) { | |||
var header_offset = $(".navbar").height() + $(".page-head").height(); | |||
var top = $(element).offset().top - header_offset - cint(additional_offset); | |||
if (animate) { | |||
$("html, body").animate({ scrollTop: top }); | |||
} else { | |||
$(window).scrollTop(top); | |||
} | |||
} | |||
}); |
@@ -50,24 +50,27 @@ frappe.search.utils = { | |||
find(values, keywords, function(match) { | |||
var out = { | |||
route: match[1] | |||
} | |||
if(match[1][0]==='Form' && match[1][2]) { | |||
if(match[1][1] !== match[1][2]) { | |||
}; | |||
if (match[1][0]==='Form') { | |||
if (match[1].length > 2 && match[1][1] !== match[1][2]) { | |||
out.label = __(match[1][1]) + " " + match[1][2].bold(); | |||
out.value = __(match[1][1]) + " " + match[1][2]; | |||
} else { | |||
out.label = __(match[1][1]).bold(); | |||
out.value = __(match[1][1]); | |||
} | |||
} else if(in_list(['List', 'Report', 'Tree', 'modules', 'query-report'], match[1][0])) { | |||
} else if (in_list(['List', 'Report', 'Tree', 'modules', 'query-report'], match[1][0]) && (match[1].length > 1)) { | |||
var type = match[1][0], label = type; | |||
if(type==='modules') label = 'Module'; | |||
else if(type==='query-report') label = 'Report'; | |||
out.label = __(match[1][1]).bold() + " " + __(label); | |||
out.value = __(match[1][1]) + " " + __(label); | |||
} else { | |||
} else if (match[0]) { | |||
out.label = match[0].bold(); | |||
out.value = match[0]; | |||
} else { | |||
// eslint-disable-next-line | |||
console.log('Illegal match', match); | |||
} | |||
out.index = 80; | |||
return out; | |||
@@ -492,7 +492,8 @@ _f.Frm.prototype.make_new = function(doctype) { | |||
} | |||
}); | |||
frappe.set_route('Form', doctype, new_doc.name); | |||
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); | |||
// frappe.set_route('Form', doctype, new_doc.name); | |||
}); | |||
} | |||
} | |||
@@ -225,7 +225,7 @@ _f.Frm.prototype.watch_model_updates = function() { | |||
}; | |||
_f.Frm.prototype.setup_std_layout = function() { | |||
this.form_wrapper = $('<div></div>').appendTo(this.layout_main); | |||
this.form_wrapper = $('<div></div>').appendTo(this.layout_main); | |||
this.body = $('<div></div>').appendTo(this.form_wrapper); | |||
// only tray | |||
@@ -53,7 +53,7 @@ def clear_global_cache(): | |||
frappe.model.meta.clear_cache() | |||
frappe.cache().delete_value(["app_hooks", "installed_apps", | |||
"app_modules", "module_app", "notification_config", 'system_settings' | |||
'scheduler_events', 'time_zone', 'webhooks']) | |||
'scheduler_events', 'time_zone', 'webhooks', 'active_domains', 'active_modules']) | |||
frappe.setup_module_map() | |||
@@ -1,15 +1,11 @@ | |||
frappe.tests = { | |||
data: {}, | |||
get_fixture_names: (doctype) => { | |||
return Object.keys(frappe.test_data[doctype]); | |||
}, | |||
make: function(doctype, data) { | |||
return frappe.run_serially([ | |||
() => frappe.set_route('List', doctype), | |||
() => frappe.new_doc(doctype), | |||
() => { | |||
if (frappe.quick_entry) | |||
{ | |||
if (frappe.quick_entry) { | |||
frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(); | |||
return frappe.timeout(1); | |||
} | |||
@@ -79,13 +75,13 @@ frappe.tests = { | |||
}); | |||
return frappe.run_serially(grid_row_tasks); | |||
}, | |||
setup_doctype: (doctype) => { | |||
setup_doctype: (doctype, data) => { | |||
return frappe.run_serially([ | |||
() => frappe.set_route('List', doctype), | |||
() => frappe.timeout(1), | |||
() => { | |||
frappe.tests.data[doctype] = []; | |||
let expected = frappe.tests.get_fixture_names(doctype); | |||
let expected = Object.keys(data); | |||
cur_list.data.forEach((d) => { | |||
frappe.tests.data[doctype].push(d.name); | |||
if(expected.indexOf(d.name) !== -1) { | |||
@@ -98,7 +94,7 @@ frappe.tests = { | |||
expected.forEach(function(d) { | |||
if(d) { | |||
tasks.push(() => frappe.tests.make(doctype, | |||
frappe.test_data[doctype][d])); | |||
data[d])); | |||
} | |||
}); | |||
@@ -84,16 +84,19 @@ class TestDriver(object): | |||
time.sleep(0.2) | |||
def set_field(self, fieldname, text): | |||
elem = self.find(xpath='//input[@data-fieldname="{0}"]'.format(fieldname)) | |||
elem[0].send_keys(text) | |||
elem = self.wait_for(xpath='//input[@data-fieldname="{0}"]'.format(fieldname)) | |||
time.sleep(0.2) | |||
elem.send_keys(text) | |||
def set_select(self, fieldname, text): | |||
elem = self.find(xpath='//select[@data-fieldname="{0}"]'.format(fieldname)) | |||
elem[0].send_keys(text) | |||
elem = self.wait_for(xpath='//select[@data-fieldname="{0}"]'.format(fieldname)) | |||
time.sleep(0.2) | |||
elem.send_keys(text) | |||
def set_text_editor(self, fieldname, text): | |||
elem = self.find(xpath='//div[@data-fieldname="{0}"]//div[@contenteditable="true"]'.format(fieldname)) | |||
elem[0].send_keys(text) | |||
elem = self.wait_for(xpath='//div[@data-fieldname="{0}"]//div[@contenteditable="true"]'.format(fieldname)) | |||
time.sleep(0.2) | |||
elem.send_keys(text) | |||
def find(self, selector=None, everywhere=False, xpath=None): | |||
if xpath: | |||
@@ -164,7 +167,11 @@ class TestDriver(object): | |||
self.wait_for(xpath='//div[@data-page-route="{0}"]'.format('/'.join(args)), timeout=4) | |||
def click(self, css_selector, xpath=None): | |||
self.wait_till_clickable(css_selector, xpath).click() | |||
element = self.wait_till_clickable(css_selector, xpath) | |||
self.scroll_to(css_selector) | |||
time.sleep(0.5) | |||
element.click() | |||
return element | |||
def click_primary_action(self): | |||
selector = ".page-actions .primary-action" | |||
@@ -201,6 +208,7 @@ class TestDriver(object): | |||
return self.get_wait().until(EC.element_to_be_clickable( | |||
(by, selector))) | |||
def execute_script(self, js): | |||
self.driver.execute_script(js) | |||