diff --git a/frappe/__init__.py b/frappe/__init__.py
index 2e0b543a06..694cb30e93 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -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 = {}
diff --git a/frappe/build.js b/frappe/build.js
index 9a4f0c2fc9..de12e31ca0 100644
--- a/frappe/build.js
+++ b/frappe/build.js
@@ -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();
});
diff --git a/frappe/core/doctype/domain/domain.py b/frappe/core/doctype/domain/domain.py
index d8a571537c..c6b1766235 100644
--- a/frappe/core/doctype/domain/domain.py
+++ b/frappe/core/doctype/domain/domain.py
@@ -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])))
diff --git a/frappe/core/doctype/domain_settings/domain_settings.py b/frappe/core/doctype/domain_settings/domain_settings.py
index cfe5010835..b3e1b133ae 100644
--- a/frappe/core/doctype/domain_settings/domain_settings.py
+++ b/frappe/core/doctype/domain_settings/domain_settings.py
@@ -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'])
diff --git a/frappe/core/doctype/system_settings/system_settings.py b/frappe/core/doctype/system_settings/system_settings.py
index ef2863fd46..bd35edb880 100644
--- a/frappe/core/doctype/system_settings/system_settings.py
+++ b/frappe/core/doctype/system_settings/system_settings.py
@@ -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:
diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py
index 6eb3eef544..a94608f25d 100644
--- a/frappe/custom/doctype/custom_field/custom_field.py
+++ b/frappe/custom/doctype/custom_field/custom_field.py
@@ -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:
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.js b/frappe/desk/page/setup_wizard/setup_wizard.js
index f83f1c57ed..bc4ce4f043 100644
--- a/frappe/desk/page/setup_wizard/setup_wizard.js
+++ b/frappe/desk/page/setup_wizard/setup_wizard.js
@@ -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);
});
},
diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py
index 09afea8b3d..8b6f32536c 100644
--- a/frappe/desk/reportview.py
+++ b/frappe/desk/reportview.py
@@ -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]])
diff --git a/frappe/patches.txt b/frappe/patches.txt
index 86015c001c..ce5cc760dd 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -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
diff --git a/frappe/public/js/frappe/db.js b/frappe/public/js/frappe/db.js
index 101228de97..3cc34e3f79 100644
--- a/frappe/public/js/frappe/db.js
+++ b/frappe/public/js/frappe/db.js
@@ -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",
diff --git a/frappe/public/js/frappe/form/controls/base_control.js b/frappe/public/js/frappe/form/controls/base_control.js
index 68cd4b0da9..68a1138584 100644
--- a/frappe/public/js/frappe/form/controls/base_control.js
+++ b/frappe/public/js/frappe/form/controls/base_control.js
@@ -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)) {
diff --git a/frappe/public/js/frappe/form/controls/base_input.js b/frappe/public/js/frappe/form/controls/base_input.js
index 5e93009202..99edde9936 100644
--- a/frappe/public/js/frappe/form/controls/base_input.js
+++ b/frappe/public/js/frappe/form/controls/base_input.js
@@ -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);
diff --git a/frappe/public/js/frappe/form/controls/data.js b/frappe/public/js/frappe/form/controls/data.js
index 5751451f27..aa78f2df8e 100644
--- a/frappe/public/js/frappe/form/controls/data.js
+++ b/frappe/public/js/frappe/form/controls/data.js
@@ -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) {
diff --git a/frappe/public/js/frappe/form/controls/password.js b/frappe/public/js/frappe/form/controls/password.js
index 5ea940d577..8a25642737 100644
--- a/frappe/public/js/frappe/form/controls/password.js
+++ b/frappe/public/js/frappe/form/controls/password.js
@@ -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) {
diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js
index 2334ab9876..ea04faa865 100644
--- a/frappe/public/js/frappe/form/layout.js
+++ b/frappe/public/js/frappe/form/layout.js
@@ -25,7 +25,7 @@ frappe.ui.form.Layout = Class.extend({
this.wrapper = $('
').appendTo(this.parent);
this.message = $('
').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)!=='<') {
diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js
index 015cc27ded..f3f5e55d71 100644
--- a/frappe/public/js/frappe/form/quick_entry.js
+++ b/frappe/public/js/frappe/form/quick_entry.js
@@ -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);
}
diff --git a/frappe/public/js/frappe/form/save.js b/frappe/public/js/frappe/form/save.js
index 4fd5aab626..3aadb8c314 100644
--- a/frappe/public/js/frappe/form/save.js
+++ b/frappe/public/js/frappe/form/save.js
@@ -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;
diff --git a/frappe/public/js/frappe/misc/common.js b/frappe/public/js/frappe/misc/common.js
index c01921f6aa..264ca8aae0 100644
--- a/frappe/public/js/frappe/misc/common.js
+++ b/frappe/public/js/frappe/misc/common.js
@@ -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';
diff --git a/frappe/public/js/frappe/model/model.js b/frappe/public/js/frappe/model/model.js
index 0a58c410b5..81f0249480 100644
--- a/frappe/public/js/frappe/model/model.js
+++ b/frappe/public/js/frappe/model/model.js
@@ -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;
diff --git a/frappe/public/js/frappe/request.js b/frappe/public/js/frappe/request.js
index 1d4bfdddfc..de474538ab 100644
--- a/frappe/public/js/frappe/request.js
+++ b/frappe/public/js/frappe/request.js
@@ -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);
}
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index 05be95e9fc..2c4477e1e6 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -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 = $(`
-
${filename} changed Click to Reload
- `)
- 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 = $(`
+ //
${filename} changed Click to Reload
+ // `)
+ // msg.find('a').click(frappe.ui.toolbar.clear_cache);
+ // frappe.show_alert({
+ // indicator: 'orange',
+ // message: msg
+ // }, 5);
+ // });
},
process_response: function(data, method) {
if(!data) {
diff --git a/frappe/public/js/frappe/ui/page.js b/frappe/public/js/frappe/ui/page.js
index 21fcc9e46b..5fde62d898 100644
--- a/frappe/public/js/frappe/ui/page.js
+++ b/frappe/public/js/frappe/ui/page.js
@@ -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);
- }
-}
+});
\ No newline at end of file
diff --git a/frappe/public/js/frappe/ui/toolbar/search_utils.js b/frappe/public/js/frappe/ui/toolbar/search_utils.js
index f355e8547b..c434bef88f 100644
--- a/frappe/public/js/frappe/ui/toolbar/search_utils.js
+++ b/frappe/public/js/frappe/ui/toolbar/search_utils.js
@@ -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;
diff --git a/frappe/public/js/legacy/clientscriptAPI.js b/frappe/public/js/legacy/clientscriptAPI.js
index c7590c5ae5..dc715defe8 100644
--- a/frappe/public/js/legacy/clientscriptAPI.js
+++ b/frappe/public/js/legacy/clientscriptAPI.js
@@ -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);
});
}
}
diff --git a/frappe/public/js/legacy/form.js b/frappe/public/js/legacy/form.js
index 413e1e594a..b526f9b6c8 100644
--- a/frappe/public/js/legacy/form.js
+++ b/frappe/public/js/legacy/form.js
@@ -225,7 +225,7 @@ _f.Frm.prototype.watch_model_updates = function() {
};
_f.Frm.prototype.setup_std_layout = function() {
- this.form_wrapper = $('
').appendTo(this.layout_main);
+ this.form_wrapper = $('
').appendTo(this.layout_main);
this.body = $('
').appendTo(this.form_wrapper);
// only tray
diff --git a/frappe/sessions.py b/frappe/sessions.py
index c25ccadced..379385ac2f 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -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()
diff --git a/frappe/tests/ui/data/test_lib.js b/frappe/tests/ui/data/test_lib.js
index 71ba61efaa..a6ca8a4628 100644
--- a/frappe/tests/ui/data/test_lib.js
+++ b/frappe/tests/ui/data/test_lib.js
@@ -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]));
}
});
diff --git a/frappe/utils/selenium_testdriver.py b/frappe/utils/selenium_testdriver.py
index f19d42d593..3f3d82fe43 100644
--- a/frappe/utils/selenium_testdriver.py
+++ b/frappe/utils/selenium_testdriver.py
@@ -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)