[refactor] domain and domain settings (#4163)
* [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 dashboard
This commit is contained in:
parent
6efcd2e13d
commit
f0e23a5a6c
28 changed files with 299 additions and 145 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue