Merge branch 'develop' into event-last-update

This commit is contained in:
Suraj Shetty 2021-12-03 20:09:03 +05:30 committed by GitHub
commit 404856bc61
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 122 additions and 30 deletions

View file

@ -32,6 +32,12 @@ jobs:
with:
python-version: '3.9'
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: 14
check-latest: true
- name: Check if build should be run
id: check-build
run: |

View file

@ -1,16 +1,6 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
// -------------
// Menu Display
// -------------
// $(cur_frm.wrapper).on("grid-row-render", function(e, grid_row) {
// if(grid_row.doc && grid_row.doc.fieldtype=="Section Break") {
// $(grid_row.row).css({"font-weight": "bold"});
// }
// })
frappe.ui.form.on('DocType', {
refresh: function(frm) {
frm.set_query('role', 'permissions', function(doc) {
@ -129,7 +119,7 @@ frappe.ui.form.on('DocType', {
}
frm.set_df_property('fields', 'reqd', frm.doc.autoname !== 'Prompt');
}
},
});
frappe.ui.form.on("DocField", {
@ -217,5 +207,11 @@ frappe.ui.form.on("DocField", {
$doctype_select.val(curr_value.doctype);
update_fieldname_options();
}
},
fieldtype: function(frm) {
frm.trigger("max_attachments");
}
});
extend_cscript(cur_frm.cscript, new frappe.model.DocTypeController({frm: cur_frm}));

View file

@ -75,6 +75,7 @@ class DocType(Document):
self.make_repeatable()
self.validate_nestedset()
self.validate_website()
self.ensure_minimum_max_attachment_limit()
validate_links_table_fieldnames(self)
if not self.is_new():
@ -246,6 +247,22 @@ class DocType(Document):
# clear website cache
clear_cache()
def ensure_minimum_max_attachment_limit(self):
"""Ensure that max_attachments is *at least* bigger than number of attach fields."""
from frappe.model import attachment_fieldtypes
if not self.max_attachments:
return
total_attach_fields = len([d for d in self.fields if d.fieldtype in attachment_fieldtypes])
if total_attach_fields > self.max_attachments:
self.max_attachments = total_attach_fields
field_label = frappe.bold(self.meta.get_field("max_attachments").label)
frappe.msgprint(_("Number of attachment fields are more than {}, limit updated to {}.")
.format(field_label, total_attach_fields),
title=_("Insufficient attachment limit"), alert=True)
def change_modified_of_parent(self):
"""Change the timestamp of parent DocType if the current one is a child to clear caches."""
if frappe.flags.in_import:

View file

@ -332,3 +332,4 @@ frappe.customize_form.clear_locals_and_refresh = function(frm) {
frm.refresh();
}
extend_cscript(cur_frm.cscript, new frappe.model.DocTypeController({frm: cur_frm}));

View file

@ -171,10 +171,10 @@ class Database(object):
frappe.errprint(query)
elif self.is_deadlocked(e):
raise frappe.QueryDeadlockError
raise frappe.QueryDeadlockError(e)
elif self.is_timedout(e):
raise frappe.QueryTimeoutError
raise frappe.QueryTimeoutError(e)
if ignore_ddl and (self.is_missing_column(e) or self.is_missing_table(e) or self.cant_drop_field_or_key(e)):
pass
@ -583,7 +583,7 @@ class Database(object):
if not isinstance(fields, Criterion):
for field in fields:
if "(" in field or " as " in field:
if "(" in str(field) or " as " in str(field):
field_objects.append(PseudoColumn(field))
else:
field_objects.append(field)
@ -842,7 +842,7 @@ class Database(object):
cache_count = frappe.cache().get_value('doctype:count:{}'.format(dt))
if cache_count is not None:
return cache_count
query = self.query.build_conditions(table=dt, filters=filters).select(Count("*"))
query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"))
if filters:
count = self.sql(query, debug=debug)[0][0]
return count

View file

@ -2,6 +2,17 @@
// For license information, please see license.txt
frappe.ui.form.on("Onboarding Step", {
setup: function(frm) {
frm.set_query("form_tour", function() {
return {
filters: {
reference_doctype: frm.doc.reference_document
}
};
});
},
refresh: function(frm) {
frappe.boot.developer_mode &&
frm.set_intro(

View file

@ -20,6 +20,7 @@
"reference_document",
"show_full_form",
"show_form_tour",
"form_tour",
"is_single",
"reference_report",
"report_reference_doctype",
@ -206,13 +207,21 @@
"fieldname": "show_form_tour",
"fieldtype": "Check",
"label": "Show Form Tour"
},
{
"depends_on": "show_form_tour",
"fieldname": "form_tour",
"fieldtype": "Link",
"label": "Form Tour",
"options": "Form Tour"
}
],
"links": [],
"modified": "2020-10-30 14:54:06.646513",
"modified": "2021-12-02 10:56:04.448580",
"modified_by": "Administrator",
"module": "Desk",
"name": "Onboarding Step",
"naming_rule": "Set by user",
"owner": "Administrator",
"permissions": [
{

View file

@ -186,12 +186,13 @@ class Newsletter(WebsiteGenerator):
frappe.db.auto_commit_on_many_writes = is_auto_commit_set
def get_message(self) -> str:
if self.content_type == "HTML":
return frappe.render_template(self.message_html, {"doc": self.as_dict()})
message = self.message
if self.content_type == "Markdown":
return frappe.utils.markdown(self.message_md)
# fallback to Rich Text
return self.message
message = frappe.utils.md_to_html(self.message_md)
if self.content_type == "HTML":
message = self.message_html
return frappe.render_template(message, {"doc": self.as_dict()})
def get_recipients(self) -> List[str]:
"""Get recipients from Email Group"""

View file

@ -324,7 +324,7 @@ def _delete_doctypes(doctypes: List[str], dry_run: bool) -> None:
print(f"* dropping Table for '{doctype}'...")
if not dry_run:
frappe.delete_doc("DocType", doctype, ignore_on_trash=True)
frappe.db.sql_ddl(f"drop table `tab{doctype}`")
frappe.db.sql_ddl(f"DROP TABLE IF EXISTS `tab{doctype}`")
def post_install(rebuild_website=False):

View file

@ -38,6 +38,11 @@ data_fieldtypes = (
'Icon'
)
attachment_fieldtypes = (
'Attach',
'Attach Image',
)
no_value_fields = (
'Section Break',
'Column Break',

View file

@ -14,4 +14,4 @@ import "./frappe/form/controls/control.js";
import "./frappe/views/formview.js";
import "./frappe/form/form.js";
import "./frappe/meta_tag.js";
import "./frappe/doctype/"

View file

@ -0,0 +1,23 @@
frappe.provide("frappe.model");
/*
Common class for handling client side interactions that
apply to both DocType form and customize form.
*/
frappe.model.DocTypeController = class DocTypeController extends frappe.ui.form.Controller {
max_attachments() {
if (!this.frm.doc.max_attachments) {
return;
}
const is_attach_field = (f) => ["Attach", "Attach Image"].includes(f.fieldtype);
const no_of_attach_fields = this.frm.doc.fields.filter(is_attach_field).length;
if (no_of_attach_fields > this.frm.doc.max_attachments) {
this.frm.set_value("max_attachments", no_of_attach_fields);
const label = this.frm.get_docfield("max_attachments").label;
frappe.show_alert(
__("Number of attachment fields are more than {}, limit updated to {}.", [label, no_of_attach_fields]));
}
}
}

View file

@ -234,8 +234,9 @@ export default class OnboardingWidget extends Widget {
},
});
};
const tour_name = step.form_tour;
frm.tour
.init({ on_finish })
.init({ tour_name, on_finish })
.then(() => frm.tour.start());
};
@ -328,8 +329,9 @@ export default class OnboardingWidget extends Widget {
this.mark_complete(step);
};
};
const tour_name = step.form_tour;
frm.tour
.init({ on_finish })
.init({ tour_name, on_finish })
.then(() => frm.tour.start());
};

View file

@ -266,7 +266,8 @@ h5.modal-title {
.login-content.container {
background-color: var(--fg-color);
padding: 45px 0px;
padding-bottom: 45px;
padding-top: 45px;
box-shadow: var(--shadow-base);
border-radius: var(--border-radius-md);
max-width: 400px;

View file

@ -24,10 +24,30 @@ class TestDB(unittest.TestCase):
self.assertNotEqual(frappe.db.get_value("User", {"name": ["!=", "Guest"]}), "Guest")
self.assertEqual(frappe.db.get_value("User", {"name": ["<", "Adn"]}), "Administrator")
self.assertEqual(frappe.db.get_value("User", {"name": ["<=", "Administrator"]}), "Administrator")
self.assertEqual(frappe.db.get_value("User", {}, ["Max(name)"], order_by=None), frappe.db.sql("SELECT Max(name) FROM tabUser")[0][0])
self.assertEqual(frappe.db.get_value("User", {}, "Min(name)", order_by=None), frappe.db.sql("SELECT Min(name) FROM tabUser")[0][0])
self.assertIn("for update", frappe.db.get_value("User", Field("name") == "Administrator", for_update=True, run=False).lower())
self.assertEqual(
frappe.db.get_value("User", {}, ["Max(name)"], order_by=None),
frappe.db.sql("SELECT Max(name) FROM tabUser")[0][0],
)
self.assertEqual(
frappe.db.get_value("User", {}, "Min(name)", order_by=None),
frappe.db.sql("SELECT Min(name) FROM tabUser")[0][0],
)
self.assertIn(
"for update",
frappe.db.get_value(
"User", Field("name") == "Administrator", for_update=True, run=False
).lower(),
)
doctype = frappe.qb.DocType("User")
self.assertEqual(
frappe.qb.from_(doctype).select(doctype.name, doctype.email).run(),
frappe.db.get_values(
doctype,
filters={},
fieldname=[doctype.name, doctype.email],
order_by=None,
),
)
self.assertEqual(frappe.db.sql("""SELECT name FROM `tabUser` WHERE name > 's' ORDER BY MODIFIED DESC""")[0][0],
frappe.db.get_value("User", {"name": [">", "s"]}))