Merge branch 'develop' into disable_change_log
This commit is contained in:
commit
d7b42e34fc
26 changed files with 738 additions and 681 deletions
|
|
@ -59,7 +59,7 @@ context('Data Control', () => {
|
|||
//Checking for the error message
|
||||
cy.get('.modal-title').should('have.text', 'Message');
|
||||
cy.get('.msgprint').should('have.text', '@@### is not a valid Name');
|
||||
cy.get('.modal').type('{esc}');
|
||||
cy.hide_dialog();
|
||||
|
||||
cy.get_field('name1', 'Data').clear({force: true});
|
||||
cy.fill_field('name1', 'Komal{}/!', 'Data');
|
||||
|
|
@ -67,10 +67,10 @@ context('Data Control', () => {
|
|||
cy.findByRole('button', {name: 'Save'}).click();
|
||||
cy.get('.modal-title').should('have.text', 'Message');
|
||||
cy.get('.msgprint').should('have.text', 'Komal{}/! is not a valid Name');
|
||||
cy.hide_dialog();
|
||||
});
|
||||
|
||||
it('Verifying data control by inputting different patterns for "Email" field', () => {
|
||||
cy.get('.modal-actions > .btn-modal-close').trigger("click");
|
||||
cy.get_field('name1', 'Data').clear({force: true});
|
||||
cy.fill_field('name1', 'Komal', 'Data');
|
||||
cy.get_field('email', 'Data').clear({force: true});
|
||||
|
|
@ -79,17 +79,17 @@ context('Data Control', () => {
|
|||
cy.findByRole('button', {name: 'Save'}).click();
|
||||
cy.get('.modal-title').should('have.text', 'Message');
|
||||
cy.get('.msgprint').should('have.text', 'komal is not a valid Email Address');
|
||||
cy.get('.modal-actions > .btn-modal-close').trigger("click");
|
||||
cy.hide_dialog();
|
||||
cy.get_field('email', 'Data').clear({force: true});
|
||||
cy.fill_field('email', 'komal@test', 'Data');
|
||||
cy.get('.frappe-control[data-fieldname="email"]').should('have.class', 'has-error');
|
||||
cy.findByRole('button', {name: 'Save'}).click();
|
||||
cy.get('.modal-title').should('have.text', 'Message');
|
||||
cy.get('.msgprint').should('have.text', 'komal@test is not a valid Email Address');
|
||||
cy.hide_dialog();
|
||||
});
|
||||
|
||||
it('Verifying data control by inputting different patterns for "Phone" field', () => {
|
||||
cy.get('.modal-actions > .btn-modal-close').trigger("click");
|
||||
cy.get_field('email', 'Data').clear({force: true});
|
||||
cy.fill_field('email', 'komal@test.com', 'Data');
|
||||
cy.get_field('phone', 'Data').clear({force: true});
|
||||
|
|
@ -98,7 +98,7 @@ context('Data Control', () => {
|
|||
cy.findByRole('button', {name: 'Save'}).click({force: true});
|
||||
cy.get('.modal-title').should('have.text', 'Message');
|
||||
cy.get('.msgprint').should('have.text', 'komal is not a valid Phone Number');
|
||||
cy.get('.modal-actions > .btn-modal-close').trigger("click");
|
||||
cy.hide_dialog();
|
||||
});
|
||||
|
||||
it('Inputting correct data and saving the doc', () => {
|
||||
|
|
@ -124,6 +124,6 @@ context('Data Control', () => {
|
|||
cy.get('.actions-btn-group > .btn').contains('Actions').click();
|
||||
cy.get('.actions-btn-group > .dropdown-menu [data-label="Delete"]').click();
|
||||
cy.click_modal_primary_button('Yes');
|
||||
cy.get('.btn-modal-close').click();
|
||||
cy.hide_dialog();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
context('Form Tour', () => {
|
||||
context.skip('Form Tour', () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit('/app/form-tour');
|
||||
cy.visit('/app');
|
||||
return cy.window().its('frappe').then(frappe => {
|
||||
return frappe.call("frappe.tests.ui_test_helpers.create_form_tour");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ def msgprint(
|
|||
if as_table and type(msg) in (list, tuple):
|
||||
out.as_table = 1
|
||||
|
||||
if as_list and type(msg) in (list, tuple) and len(msg) > 1:
|
||||
if as_list and type(msg) in (list, tuple):
|
||||
out.as_list = 1
|
||||
|
||||
if flags.print_messages and out.message:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
"language",
|
||||
"column_break_3",
|
||||
"time_zone",
|
||||
"is_first_startup",
|
||||
"enable_onboarding",
|
||||
"setup_complete",
|
||||
"date_and_number_format",
|
||||
|
|
@ -104,14 +103,6 @@
|
|||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "is_first_startup",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Is First Startup",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "setup_complete",
|
||||
|
|
@ -509,7 +500,7 @@
|
|||
"icon": "fa fa-cog",
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2022-04-28 14:31:50.330954",
|
||||
"modified": "2022-05-09 18:53:35.218721",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "System Settings",
|
||||
|
|
|
|||
|
|
@ -1019,21 +1019,17 @@ class Database(object):
|
|||
|
||||
return self.get_value(dt, dn, ignore=True, cache=cache)
|
||||
|
||||
def count(self, dt, filters=None, debug=False, cache=False):
|
||||
def count(self, dt, filters=None, debug=False, cache=False, distinct: bool = True):
|
||||
"""Returns `COUNT(*)` for given DocType and filters."""
|
||||
if cache and not filters:
|
||||
cache_count = frappe.cache().get_value("doctype:count:{}".format(dt))
|
||||
if cache_count is not None:
|
||||
return cache_count
|
||||
query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"))
|
||||
if filters:
|
||||
count = self.sql(query, debug=debug)[0][0]
|
||||
return count
|
||||
else:
|
||||
count = self.sql(query, debug=debug)[0][0]
|
||||
if cache:
|
||||
frappe.cache().set_value("doctype:count:{}".format(dt), count, expires_in_sec=86400)
|
||||
return count
|
||||
query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"), distinct=distinct)
|
||||
count = query.run(debug=debug)[0][0]
|
||||
if not filters and cache:
|
||||
frappe.cache().set_value("doctype:count:{}".format(dt), count, expires_in_sec=86400)
|
||||
return count
|
||||
|
||||
@staticmethod
|
||||
def format_date(date):
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ from typing import Any, Dict, List, Tuple, Union
|
|||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.query_builder import Criterion, Field, Order
|
||||
from frappe.query_builder import Criterion, Field, Order, Table
|
||||
|
||||
|
||||
def like(key: str, value: str) -> frappe.qb:
|
||||
def like(key: Field, value: str) -> frappe.qb:
|
||||
"""Wrapper method for `LIKE`
|
||||
|
||||
Args:
|
||||
|
|
@ -17,10 +17,10 @@ def like(key: str, value: str) -> frappe.qb:
|
|||
Returns:
|
||||
frappe.qb: `frappe.qb object with `LIKE`
|
||||
"""
|
||||
return Field(key).like(value)
|
||||
return key.like(value)
|
||||
|
||||
|
||||
def func_in(key: str, value: Union[List, Tuple]) -> frappe.qb:
|
||||
def func_in(key: Field, value: Union[List, Tuple]) -> frappe.qb:
|
||||
"""Wrapper method for `IN`
|
||||
|
||||
Args:
|
||||
|
|
@ -30,10 +30,10 @@ def func_in(key: str, value: Union[List, Tuple]) -> frappe.qb:
|
|||
Returns:
|
||||
frappe.qb: `frappe.qb object with `IN`
|
||||
"""
|
||||
return Field(key).isin(value)
|
||||
return key.isin(value)
|
||||
|
||||
|
||||
def not_like(key: str, value: str) -> frappe.qb:
|
||||
def not_like(key: Field, value: str) -> frappe.qb:
|
||||
"""Wrapper method for `NOT LIKE`
|
||||
|
||||
Args:
|
||||
|
|
@ -43,10 +43,10 @@ def not_like(key: str, value: str) -> frappe.qb:
|
|||
Returns:
|
||||
frappe.qb: `frappe.qb object with `NOT LIKE`
|
||||
"""
|
||||
return Field(key).not_like(value)
|
||||
return key.not_like(value)
|
||||
|
||||
|
||||
def func_not_in(key: str, value: Union[List, Tuple]):
|
||||
def func_not_in(key: Field, value: Union[List, Tuple]):
|
||||
"""Wrapper method for `NOT IN`
|
||||
|
||||
Args:
|
||||
|
|
@ -56,10 +56,10 @@ def func_not_in(key: str, value: Union[List, Tuple]):
|
|||
Returns:
|
||||
frappe.qb: `frappe.qb object with `NOT IN`
|
||||
"""
|
||||
return Field(key).notin(value)
|
||||
return key.notin(value)
|
||||
|
||||
|
||||
def func_regex(key: str, value: str) -> frappe.qb:
|
||||
def func_regex(key: Field, value: str) -> frappe.qb:
|
||||
"""Wrapper method for `REGEX`
|
||||
|
||||
Args:
|
||||
|
|
@ -69,10 +69,10 @@ def func_regex(key: str, value: str) -> frappe.qb:
|
|||
Returns:
|
||||
frappe.qb: `frappe.qb object with `REGEX`
|
||||
"""
|
||||
return Field(key).regex(value)
|
||||
return key.regex(value)
|
||||
|
||||
|
||||
def func_between(key: str, value: Union[List, Tuple]) -> frappe.qb:
|
||||
def func_between(key: Field, value: Union[List, Tuple]) -> frappe.qb:
|
||||
"""Wrapper method for `BETWEEN`
|
||||
|
||||
Args:
|
||||
|
|
@ -82,7 +82,7 @@ def func_between(key: str, value: Union[List, Tuple]) -> frappe.qb:
|
|||
Returns:
|
||||
frappe.qb: `frappe.qb object with `BETWEEN`
|
||||
"""
|
||||
return Field(key)[slice(*value)]
|
||||
return key[slice(*value)]
|
||||
|
||||
|
||||
def make_function(key: Any, value: Union[int, str]):
|
||||
|
|
@ -139,7 +139,9 @@ OPERATOR_MAP = {
|
|||
|
||||
|
||||
class Query:
|
||||
def get_condition(self, table: str, **kwargs) -> frappe.qb:
|
||||
tables: dict = {}
|
||||
|
||||
def get_condition(self, table: Union[str, Table], **kwargs) -> frappe.qb:
|
||||
"""Get initial table object
|
||||
|
||||
Args:
|
||||
|
|
@ -148,11 +150,20 @@ class Query:
|
|||
Returns:
|
||||
frappe.qb: DocType with initial condition
|
||||
"""
|
||||
table_object = self.get_table(table)
|
||||
if kwargs.get("update"):
|
||||
return frappe.qb.update(table)
|
||||
return frappe.qb.update(table_object)
|
||||
if kwargs.get("into"):
|
||||
return frappe.qb.into(table)
|
||||
return frappe.qb.from_(table)
|
||||
return frappe.qb.into(table_object)
|
||||
return frappe.qb.from_(table_object)
|
||||
|
||||
def get_table(self, table_name: Union[str, Table]) -> Table:
|
||||
if isinstance(table_name, Table):
|
||||
return table_name
|
||||
table_name = table_name.strip('"').strip("'")
|
||||
if table_name not in self.tables:
|
||||
self.tables[table_name] = frappe.qb.DocType(table_name)
|
||||
return self.tables[table_name]
|
||||
|
||||
def criterion_query(self, table: str, criterion: Criterion, **kwargs) -> frappe.qb:
|
||||
"""Generate filters from Criterion objects
|
||||
|
|
@ -217,8 +228,13 @@ class Query:
|
|||
conditions = conditions.where(_operator(Field(filters[0]), filters[2]))
|
||||
break
|
||||
else:
|
||||
_operator = OPERATOR_MAP[f[1]]
|
||||
conditions = conditions.where(_operator(Field(f[0]), f[2]))
|
||||
_operator = OPERATOR_MAP[f[-2]]
|
||||
if len(f) == 4:
|
||||
table_object = self.get_table(f[0])
|
||||
_field = table_object[f[1]]
|
||||
else:
|
||||
_field = Field(f[0])
|
||||
conditions = conditions.where(_operator(_field, f[-1]))
|
||||
|
||||
return self.add_conditions(conditions, **kwargs)
|
||||
|
||||
|
|
@ -249,7 +265,7 @@ class Query:
|
|||
if isinstance(value, (list, tuple)):
|
||||
if isinstance(value[1], (list, tuple)) or value[0] in list(OPERATOR_MAP.keys())[-4:]:
|
||||
_operator = OPERATOR_MAP[value[0]]
|
||||
conditions = conditions.where(_operator(key, value[1]))
|
||||
conditions = conditions.where(_operator(Field(key), value[1]))
|
||||
else:
|
||||
_operator = OPERATOR_MAP[value[0]]
|
||||
conditions = conditions.where(_operator(Field(key), value[1]))
|
||||
|
|
@ -293,10 +309,19 @@ class Query:
|
|||
self,
|
||||
table: str,
|
||||
fields: Union[List, Tuple],
|
||||
filters: Union[Dict[str, Union[str, int]], str, int] = None,
|
||||
filters: Union[Dict[str, Union[str, int]], str, int, List[Union[List, str, int]]] = None,
|
||||
**kwargs,
|
||||
):
|
||||
# Clean up state before each query
|
||||
self.tables = {}
|
||||
criterion = self.build_conditions(table, filters, **kwargs)
|
||||
|
||||
if len(self.tables) > 1:
|
||||
primary_table = self.tables[table]
|
||||
del self.tables[table]
|
||||
for table_object in self.tables.values():
|
||||
criterion = criterion.left_join(table_object).on(table_object.parent == primary_table.name)
|
||||
|
||||
if isinstance(fields, (list, tuple)):
|
||||
query = criterion.select(*kwargs.get("field_objects", fields))
|
||||
|
||||
|
|
|
|||
|
|
@ -269,7 +269,6 @@ def add_all_roles_to(name):
|
|||
def disable_future_access():
|
||||
frappe.db.set_default("desktop:home_page", "workspace")
|
||||
frappe.db.set_value("System Settings", "System Settings", "setup_complete", 1)
|
||||
frappe.db.set_value("System Settings", "System Settings", "is_first_startup", 1)
|
||||
|
||||
# Enable onboarding after install
|
||||
frappe.db.set_value("System Settings", "System Settings", "enable_onboarding", 1)
|
||||
|
|
@ -334,11 +333,6 @@ def load_user_details():
|
|||
}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def reset_is_first_startup():
|
||||
frappe.db.set_value("System Settings", "System Settings", "is_first_startup", 0)
|
||||
|
||||
|
||||
def prettify_args(args):
|
||||
# remove attachments
|
||||
for key, val in args.items():
|
||||
|
|
|
|||
|
|
@ -48,15 +48,12 @@ def get_list():
|
|||
@frappe.read_only()
|
||||
def get_count():
|
||||
args = get_form_params()
|
||||
|
||||
if is_virtual_doctype(args.doctype):
|
||||
controller = get_controller(args.doctype)
|
||||
data = controller(args.doctype).get_count(args)
|
||||
else:
|
||||
distinct = "distinct " if args.distinct == "true" else ""
|
||||
args.fields = [f"count({distinct}`tab{args.doctype}`.name) as total_count"]
|
||||
data = execute(**args)[0].get("total_count")
|
||||
|
||||
distinct = args["distinct"] == "true"
|
||||
data = frappe.db.count(args["doctype"], args["filters"], distinct=distinct)
|
||||
return data
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ frappe.patches.v14_0.save_ratings_in_fraction #23-12-2021
|
|||
frappe.patches.v14_0.transform_todo_schema
|
||||
frappe.patches.v14_0.remove_post_and_post_comment
|
||||
frappe.patches.v14_0.reset_creation_datetime
|
||||
frappe.patches.v14_0.remove_is_first_startup
|
||||
|
||||
[post_model_sync]
|
||||
frappe.patches.v14_0.drop_data_import_legacy
|
||||
|
|
|
|||
8
frappe/patches/v14_0/remove_is_first_startup.py
Normal file
8
frappe/patches/v14_0/remove_is_first_startup.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
singles = frappe.qb.Table("tabSingles")
|
||||
frappe.qb.from_(singles).delete().where(
|
||||
(singles.doctype == "System Settings") & (singles.field == "is_first_startup")
|
||||
).run()
|
||||
|
|
@ -137,13 +137,13 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat
|
|||
});
|
||||
}
|
||||
parse(value) {
|
||||
if(value) {
|
||||
return frappe.datetime.user_to_str(value);
|
||||
if (value) {
|
||||
return frappe.datetime.user_to_str(value, false, true);
|
||||
}
|
||||
}
|
||||
format_for_input(value) {
|
||||
if(value) {
|
||||
return frappe.datetime.str_to_user(value);
|
||||
if (value) {
|
||||
return frappe.datetime.str_to_user(value, false, true);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@ frappe.ui.form.ControlDatetime = class ControlDatetime extends frappe.ui.form.Co
|
|||
}
|
||||
format_for_input(value) {
|
||||
if (!value) return "";
|
||||
|
||||
|
||||
return frappe.datetime.str_to_user(value, false);
|
||||
}
|
||||
set_description() {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export default class ListSettings {
|
|||
if (field_count < 4) {
|
||||
field_count = 4;
|
||||
} else if (field_count > 10) {
|
||||
field_count = 4;
|
||||
field_count = 10;
|
||||
}
|
||||
|
||||
me.dialog.set_value("total_fields", field_count);
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ $.extend(frappe.datetime, {
|
|||
return frappe.sys_defaults && frappe.sys_defaults.date_format || "yyyy-mm-dd";
|
||||
},
|
||||
|
||||
str_to_user: function(val, only_time = false) {
|
||||
str_to_user: function(val, only_time=false, only_date=false) {
|
||||
if (!val) return "";
|
||||
const user_date_fmt = frappe.datetime.get_user_date_fmt().toUpperCase();
|
||||
const user_time_fmt = frappe.datetime.get_user_time_fmt();
|
||||
|
|
@ -142,6 +142,9 @@ $.extend(frappe.datetime, {
|
|||
if (only_time) {
|
||||
let date_obj = moment(val, frappe.defaultTimeFormat);
|
||||
return date_obj.format(user_format);
|
||||
} else if (only_date) {
|
||||
let date_obj = moment(val, frappe.defaultDateFormat);
|
||||
return date_obj.format(user_date_fmt);
|
||||
} else {
|
||||
let date_obj = moment.tz(val, frappe.boot.time_zone.system);
|
||||
if (typeof val !== "string" || val.indexOf(" ") === -1) {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ frappe.ready(function() {
|
|||
window.location.replace('/login?redirect-to=' + window.location.pathname);
|
||||
}
|
||||
});
|
||||
login_required.set_message(__("You are not permitted to access this page."));
|
||||
login_required.show();
|
||||
login_required.set_message(__("You are not permitted to access this page without login."));
|
||||
}
|
||||
|
||||
function show_grid() {
|
||||
|
|
|
|||
16
frappe/public/js/lib/clusterize.min.js
vendored
16
frappe/public/js/lib/clusterize.min.js
vendored
|
|
@ -1,16 +0,0 @@
|
|||
/*! Clusterize.js - v0.17.6 - 2017-03-05
|
||||
* http://NeXTs.github.com/Clusterize.js/
|
||||
* Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */
|
||||
|
||||
;(function(q,n){"undefined"!=typeof module?module.exports=n():"function"==typeof define&&"object"==typeof define.amd?define(n):this[q]=n()})("Clusterize",function(){function q(b,a,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)}function n(b,a,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)}function r(b){return"[object Array]"===Object.prototype.toString.call(b)}function m(b,a){return window.getComputedStyle?window.getComputedStyle(a)[b]:
|
||||
a.currentStyle[b]}var l=function(){for(var b=3,a=document.createElement("b"),c=a.all||[];a.innerHTML="\x3c!--[if gt IE "+ ++b+"]><i><![endif]--\x3e",c[0];);return 4<b?b:document.documentMode}(),x=navigator.platform.toLowerCase().indexOf("mac")+1,p=function(b){if(!(this instanceof p))return new p(b);var a=this,c={rows_in_block:50,blocks_in_cluster:4,tag:null,show_no_data_row:!0,no_data_class:"clusterize-no-data",no_data_text:"No data",keep_parity:!0,callbacks:{}};a.options={};for(var d="rows_in_block blocks_in_cluster show_no_data_row no_data_class no_data_text keep_parity tag callbacks".split(" "),
|
||||
f=0,h;h=d[f];f++)a.options[h]="undefined"!=typeof b[h]&&null!=b[h]?b[h]:c[h];c=["scroll","content"];for(f=0;d=c[f];f++)if(a[d+"_elem"]=b[d+"Id"]?document.getElementById(b[d+"Id"]):b[d+"Elem"],!a[d+"_elem"])throw Error("Error! Could not find "+d+" element");a.content_elem.hasAttribute("tabindex")||a.content_elem.setAttribute("tabindex",0);var e=r(b.rows)?b.rows:a.fetchMarkup(),g={};b=a.scroll_elem.scrollTop;a.insertToDOM(e,g);a.scroll_elem.scrollTop=b;var k=!1,m=0,l=!1,t=function(){x&&(l||(a.content_elem.style.pointerEvents=
|
||||
"none"),l=!0,clearTimeout(m),m=setTimeout(function(){a.content_elem.style.pointerEvents="auto";l=!1},50));k!=(k=a.getClusterNum())&&a.insertToDOM(e,g);a.options.callbacks.scrollingProgress&&a.options.callbacks.scrollingProgress(a.getScrollProgress())},u=0,v=function(){clearTimeout(u);u=setTimeout(a.refresh,100)};q("scroll",a.scroll_elem,t);q("resize",window,v);a.destroy=function(b){n("scroll",a.scroll_elem,t);n("resize",window,v);a.html((b?a.generateEmptyRow():e).join(""))};a.refresh=function(b){(a.getRowsHeight(e)||
|
||||
b)&&a.update(e)};a.update=function(b){e=r(b)?b:[];b=a.scroll_elem.scrollTop;e.length*a.options.item_height<b&&(k=a.scroll_elem.scrollTop=0);a.insertToDOM(e,g);a.scroll_elem.scrollTop=b};a.clear=function(){a.update([])};a.getRowsAmount=function(){return e.length};a.getScrollProgress=function(){return this.options.scroll_top/(e.length*this.options.item_height)*100||0};var w=function(b,c){var d=r(c)?c:[];d.length&&(e="append"==b?e.concat(d):d.concat(e),a.insertToDOM(e,g))};a.append=function(a){w("append",
|
||||
a)};a.prepend=function(a){w("prepend",a)}};p.prototype={constructor:p,fetchMarkup:function(){for(var b=[],a=this.getChildNodes(this.content_elem);a.length;)b.push(a.shift().outerHTML);return b},exploreEnvironment:function(b,a){var c=this.options;c.content_tag=this.content_elem.tagName.toLowerCase();b.length&&(l&&9>=l&&!c.tag&&(c.tag=b[0].match(/<([^>\s/]*)/)[1].toLowerCase()),1>=this.content_elem.children.length&&(a.data=this.html(b[0]+b[0]+b[0])),c.tag||(c.tag=this.content_elem.children[0].tagName.toLowerCase()),
|
||||
this.getRowsHeight(b))},getRowsHeight:function(b){var a=this.options,c=a.item_height;a.cluster_height=0;if(b.length){b=this.content_elem.children;var d=b[Math.floor(b.length/2)];a.item_height=d.offsetHeight;"tr"==a.tag&&"collapse"!=m("borderCollapse",this.content_elem)&&(a.item_height+=parseInt(m("borderSpacing",this.content_elem),10)||0);"tr"!=a.tag&&(b=parseInt(m("marginTop",d),10)||0,d=parseInt(m("marginBottom",d),10)||0,a.item_height+=Math.max(b,d));a.block_height=a.item_height*a.rows_in_block;
|
||||
a.rows_in_cluster=a.blocks_in_cluster*a.rows_in_block;a.cluster_height=a.blocks_in_cluster*a.block_height;return c!=a.item_height}},getClusterNum:function(){this.options.scroll_top=this.scroll_elem.scrollTop;return Math.floor(this.options.scroll_top/(this.options.cluster_height-this.options.block_height))||0},generateEmptyRow:function(){var b=this.options;if(!b.tag||!b.show_no_data_row)return[];var a=document.createElement(b.tag),c=document.createTextNode(b.no_data_text),d;a.className=b.no_data_class;
|
||||
"tr"==b.tag&&(d=document.createElement("td"),d.colSpan=100,d.appendChild(c));a.appendChild(d||c);return[a.outerHTML]},generate:function(b,a){var c=this.options,d=b.length;if(d<c.rows_in_block)return{top_offset:0,bottom_offset:0,rows_above:0,rows:d?b:this.generateEmptyRow()};var f=Math.max((c.rows_in_cluster-c.rows_in_block)*a,0),h=f+c.rows_in_cluster,e=Math.max(f*c.item_height,0),c=Math.max((d-h)*c.item_height,0),d=[],g=f;for(1>e&&g++;f<h;f++)b[f]&&d.push(b[f]);return{top_offset:e,bottom_offset:c,
|
||||
rows_above:g,rows:d}},renderExtraTag:function(b,a){var c=document.createElement(this.options.tag);c.className=["clusterize-extra-row","clusterize-"+b].join(" ");a&&(c.style.height=a+"px");return c.outerHTML},insertToDOM:function(b,a){this.options.cluster_height||this.exploreEnvironment(b,a);var c=this.generate(b,this.getClusterNum()),d=c.rows.join(""),f=this.checkChanges("data",d,a),h=this.checkChanges("top",c.top_offset,a),e=this.checkChanges("bottom",c.bottom_offset,a),g=this.options.callbacks,
|
||||
k=[];f||h?(c.top_offset&&(this.options.keep_parity&&k.push(this.renderExtraTag("keep-parity")),k.push(this.renderExtraTag("top-space",c.top_offset))),k.push(d),c.bottom_offset&&k.push(this.renderExtraTag("bottom-space",c.bottom_offset)),g.clusterWillChange&&g.clusterWillChange(),this.html(k.join("")),"ol"==this.options.content_tag&&this.content_elem.setAttribute("start",c.rows_above),g.clusterChanged&&g.clusterChanged()):e&&(this.content_elem.lastChild.style.height=c.bottom_offset+"px")},html:function(b){var a=
|
||||
this.content_elem;if(l&&9>=l&&"tr"==this.options.tag){var c=document.createElement("div");for(c.innerHTML="<table><tbody>"+b+"</tbody></table>";b=a.lastChild;)a.removeChild(b);for(c=this.getChildNodes(c.firstChild.firstChild);c.length;)a.appendChild(c.shift())}else a.innerHTML=b},getChildNodes:function(b){b=b.children;for(var a=[],c=0,d=b.length;c<d;c++)a.push(b[c]);return a},checkChanges:function(b,a,c){var d=a!=c[b];c[b]=a;return d}};return p});
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import "./lib/clusterize.min.js";
|
||||
import "./frappe/views/reports/report_factory.js";
|
||||
import "./frappe/views/reports/report_view.js";
|
||||
import "./frappe/views/reports/query_report.js";
|
||||
|
|
|
|||
|
|
@ -187,9 +187,6 @@ def get():
|
|||
bootinfo["disable_async"] = frappe.conf.disable_async
|
||||
|
||||
bootinfo["setup_complete"] = cint(frappe.db.get_single_value("System Settings", "setup_complete"))
|
||||
bootinfo["is_first_startup"] = cint(
|
||||
frappe.db.get_single_value("System Settings", "is_first_startup")
|
||||
)
|
||||
|
||||
bootinfo["desk_theme"] = frappe.db.get_value("User", frappe.session.user, "desk_theme") or "Light"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
<div class="form-group">
|
||||
<label class="form-label sr-only" for="signup_fullname">{{ _("Full Name") }}</label>
|
||||
<input type="text" id="signup_fullname" class="form-control" placeholder="{{ _('Jane Doe') }}"
|
||||
required autofocus>
|
||||
required autofocus autocomplete="name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label sr-only" for="signup_email">{{ _("Email") }}</label>
|
||||
<input type="email" id="signup_email" class="form-control"
|
||||
placeholder="{{ _('jane@example.com') }}" required>
|
||||
placeholder="{{ _('jane@example.com') }}" required autocomplete="username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-card-actions">
|
||||
|
|
|
|||
|
|
@ -482,6 +482,33 @@ class TestDB(unittest.TestCase):
|
|||
|
||||
frappe.db.delete("ToDo", {"description": test_body})
|
||||
|
||||
def test_count(self):
|
||||
frappe.db.delete("Note")
|
||||
|
||||
frappe.get_doc(doctype="Note", title="note1", content="something").insert()
|
||||
frappe.get_doc(doctype="Note", title="note2", content="someting else").insert()
|
||||
|
||||
# Count with no filtes
|
||||
self.assertEquals((frappe.db.count("Note")), 2)
|
||||
|
||||
# simple filters
|
||||
self.assertEquals((frappe.db.count("Note", ["title", "=", "note1"])), 1)
|
||||
|
||||
frappe.get_doc(doctype="Note", title="note3", content="something other").insert()
|
||||
|
||||
# List of list filters with tables
|
||||
self.assertEquals(
|
||||
(
|
||||
frappe.db.count(
|
||||
"Note",
|
||||
[["Note", "title", "like", "note%"], ["Note", "content", "like", "some%"]],
|
||||
)
|
||||
),
|
||||
3,
|
||||
)
|
||||
|
||||
frappe.db.rollback()
|
||||
|
||||
|
||||
@run_only_if(db_type_is.MARIADB)
|
||||
class TestDDLCommandsMaria(unittest.TestCase):
|
||||
|
|
|
|||
20
frappe/tests/test_query.py
Normal file
20
frappe/tests/test_query.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.tests.test_query_builder import db_type_is, run_only_if
|
||||
|
||||
|
||||
@run_only_if(db_type_is.MARIADB)
|
||||
class TestQuery(unittest.TestCase):
|
||||
def test_multiple_tables_in_filters(self):
|
||||
self.assertEqual(
|
||||
frappe.db.query.get_sql(
|
||||
"DocType",
|
||||
["*"],
|
||||
[
|
||||
["BOM Update Log", "name", "like", "f%"],
|
||||
["DocType", "parent", "=", "something"],
|
||||
],
|
||||
).get_sql(),
|
||||
"SELECT * FROM `tabDocType` LEFT JOIN `tabBOM Update Log` ON `tabBOM Update Log`.`parent`=`tabDocType`.`name` WHERE `tabBOM Update Log`.`name` LIKE 'f%' AND `tabDocType`.`parent`='something'",
|
||||
)
|
||||
|
|
@ -1,10 +1,27 @@
|
|||
import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.utils import set_request
|
||||
from frappe.website.serve import get_response
|
||||
from frappe.www.list import get_list_context
|
||||
|
||||
|
||||
class TestWebsite(unittest.TestCase):
|
||||
class TestWebform(unittest.TestCase):
|
||||
def test_webform_publish_functionality(self):
|
||||
edit_profile = frappe.get_doc("Web Form", "edit-profile")
|
||||
# publish webform
|
||||
edit_profile.published = True
|
||||
edit_profile.save()
|
||||
set_request(method="GET", path="update-profile")
|
||||
response = get_response()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# un-publish webform
|
||||
edit_profile.published = False
|
||||
edit_profile.save()
|
||||
response = get_response()
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_get_context_hook_of_webform(self):
|
||||
create_custom_doctype()
|
||||
create_webform()
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,7 +4,7 @@ from frappe.website.page_renderers.document_page import DocumentPage
|
|||
|
||||
class WebFormPage(DocumentPage):
|
||||
def can_render(self):
|
||||
webform_name = frappe.db.exists("Web Form", {"route": self.path}, cache=True)
|
||||
webform_name = frappe.db.exists("Web Form", {"route": self.path, "published": 1}, cache=True)
|
||||
if webform_name:
|
||||
self.doctype = "Web Form"
|
||||
self.docname = webform_name
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<div class="email-field">
|
||||
<input type="text" id="login_email" class="form-control"
|
||||
placeholder="{% if login_name_placeholder %}{{ login_name_placeholder }}{% else %}{{ _('jane@example.com') }}{% endif %}"
|
||||
required autofocus>
|
||||
required autofocus autocomplete="username">
|
||||
|
||||
<svg class="field-icon email-icon" width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
<div class="page-card-body">
|
||||
<div class="email-field">
|
||||
<input type="email" id="forgot_email" class="form-control"
|
||||
placeholder="{{ _('Email Address') }}" required autofocus>
|
||||
placeholder="{{ _('Email Address') }}" required autofocus autocomplete="username">
|
||||
<svg class="field-icon email-icon" width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
|
|
|
|||
|
|
@ -12,16 +12,16 @@
|
|||
<form id="reset-password">
|
||||
<div class="form-group">
|
||||
<input id="old_password" type="password"
|
||||
class="form-control mb-4" placeholder="{{ _('Old Password') }}">
|
||||
class="form-control mb-4" placeholder="{{ _('Old Password') }}" autocomplete="current-password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input id="new_password" type="password"
|
||||
class="form-control mb-4" placeholder="{{ _('New Password') }}">
|
||||
class="form-control mb-4" placeholder="{{ _('New Password') }}" autocomplete="new-password">
|
||||
<span class="password-strength-indicator indicator"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input id="confirm_password" type="password"
|
||||
class="form-control" placeholder="{{ _('Confirm Password') }}">
|
||||
class="form-control" placeholder="{{ _('Confirm Password') }}" autocomplete="new-password">
|
||||
|
||||
<p class="password-mismatch-message text-muted small hidden mt-2"></p>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue