@@ -85,6 +85,7 @@ def get_bootinfo(): | |||
bootinfo.points = get_energy_points(frappe.session.user) | |||
bootinfo.frequently_visited_links = frequently_visited_links() | |||
bootinfo.link_preview_doctypes = get_link_preview_doctypes() | |||
bootinfo.filters_config = get_filters_config() | |||
return bootinfo | |||
@@ -297,3 +298,10 @@ def get_link_preview_doctypes(): | |||
link_preview_doctypes.append(custom.doc_type) | |||
return link_preview_doctypes | |||
def get_filters_config(): | |||
filter_config = frappe._dict() | |||
filter_hooks = frappe.get_hooks('filters_config') | |||
for hook in filter_hooks: | |||
filter_config.update(frappe.get_attr(hook)()) | |||
return filter_config |
@@ -355,7 +355,9 @@ class DatabaseQuery(object): | |||
ifnull(`tabDocType`.`fieldname`, fallback) operator "value" | |||
""" | |||
f = get_filter(self.doctype, f) | |||
from frappe.boot import get_filters_config | |||
additional_filters_config = get_filters_config() | |||
f = get_filter(self.doctype, f, additional_filters_config) | |||
tname = ('`tab' + f.doctype + '`') | |||
if not tname in self.tables: | |||
@@ -369,7 +371,9 @@ class DatabaseQuery(object): | |||
can_be_null = True | |||
# prepare in condition | |||
if f.operator.lower() in additional_filters_config: | |||
f.update(get_additional_filter_field(additional_filters_config, f, f.value)) | |||
if f.operator.lower() in ('ancestors of', 'descendants of', 'not ancestors of', 'not descendants of'): | |||
values = f.value or '' | |||
@@ -853,4 +857,14 @@ def get_between_date_filter(value, df=None): | |||
frappe.db.format_date(from_date), | |||
frappe.db.format_date(to_date)) | |||
return data | |||
return data | |||
def get_additional_filter_field(additional_filters_config, f, value): | |||
additional_filter = additional_filters_config[f.operator.lower()] | |||
f = frappe._dict(frappe.get_attr(additional_filter['get_field'])()) | |||
if f.query_value: | |||
for option in f.options: | |||
option = frappe._dict(option) | |||
if option.value == value: | |||
f.value = option.query_value | |||
return f |
@@ -338,6 +338,11 @@ frappe.views.BaseList = class BaseList { | |||
: []; | |||
} | |||
get_filter_value(fieldname) { | |||
return this.get_filters_for_args().filter(f=> f[1] == fieldname)[0] && | |||
this.get_filters_for_args().filter(f=> f[1] == fieldname)[0][3]; | |||
} | |||
get_args() { | |||
return { | |||
doctype: this.doctype, | |||
@@ -6,6 +6,12 @@ frappe.ui.Filter = class { | |||
} | |||
this.utils = frappe.ui.filter_utils; | |||
this.set_conditions(); | |||
this.set_conditions_from_config(); | |||
this.make(); | |||
} | |||
set_conditions() { | |||
this.conditions = [ | |||
["=", __("Equals")], | |||
["!=", __("Not Equals")], | |||
@@ -43,10 +49,21 @@ frappe.ui.Filter = class { | |||
Color: ["Between", 'Previous', 'Current', 'Next'], | |||
Check: this.conditions.map(c => c[0]).filter(c => c !== '=') | |||
}; | |||
this.make(); | |||
this.make_select(); | |||
this.set_events(); | |||
this.setup(); | |||
} | |||
set_conditions_from_config() { | |||
if (frappe.boot.filters_config) { | |||
this.filters_config = frappe.boot.filters_config; | |||
for (let key of Object.keys(this.filters_config)) { | |||
const filter = this.filters_config[key]; | |||
this.conditions.push([key, __(`{0}`, [filter.label])]); | |||
for (let fieldtype of Object.keys(this.invalid_condition_map)) { | |||
if (!filter.fieldtypes.includes(fieldtype)) { | |||
this.invalid_condition_map[fieldtype].push(filter.label); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
make() { | |||
@@ -54,6 +71,10 @@ frappe.ui.Filter = class { | |||
conditions: this.conditions | |||
})) | |||
.appendTo(this.parent.find('.filter-edit-area')); | |||
this.make_select(); | |||
this.set_events(); | |||
this.setup(); | |||
} | |||
make_select() { | |||
@@ -121,6 +142,7 @@ frappe.ui.Filter = class { | |||
} | |||
freeze() { | |||
console.log('freeze here') | |||
this.update_filter_tag(); | |||
} | |||
@@ -230,7 +252,22 @@ frappe.ui.Filter = class { | |||
]; | |||
} | |||
this.make_field(df, cur.fieldtype); | |||
if (this.filters_config[condition] && this.filters_config[condition].fieldtypes.includes(this.field.df.fieldtype)) { | |||
let args = {}; | |||
if (this.filters_config[condition].depends_on) { | |||
const field_name = this.filters_config[condition].depends_on; | |||
const filter_value = this.base_list.get_filter_value(field_name); | |||
args[field_name] = filter_value; | |||
} | |||
frappe.xcall(this.filters_config[condition].get_field, args).then(field => { | |||
df.fieldtype = field.fieldtype; | |||
df.options = field.options; | |||
df.fieldname = fieldname; | |||
this.make_field(df, cur.fieldtype); | |||
}); | |||
} else { | |||
this.make_field(df, cur.fieldtype); | |||
} | |||
} | |||
make_field(df, old_fieldtype) { | |||
@@ -103,7 +103,8 @@ frappe.ui.FilterGroup = class { | |||
}, | |||
filter_items: (doctype, fieldname) => { | |||
return !this.filter_exists([doctype, fieldname]); | |||
} | |||
}, | |||
base_list: this.base_list | |||
}; | |||
let filter = new frappe.ui.Filter(args); | |||
this.filters.push(filter); | |||
@@ -132,7 +133,7 @@ frappe.ui.FilterGroup = class { | |||
get_filters() { | |||
return this.filters.filter(f => f.field).map(f => { | |||
f.freeze(); | |||
// f.freeze(); | |||
return f.get_value(); | |||
}); | |||
// {}: this.list.update_standard_filters(values); | |||
@@ -1011,7 +1011,7 @@ def compare(val1, condition, val2): | |||
return ret | |||
def get_filter(doctype, f): | |||
def get_filter(doctype, f, filters_config=None): | |||
"""Returns a _dict like | |||
{ | |||
@@ -1047,6 +1047,13 @@ def get_filter(doctype, f): | |||
valid_operators = ("=", "!=", ">", "<", ">=", "<=", "like", "not like", "in", "not in", "is", | |||
"between", "descendants of", "ancestors of", "not descendants of", "not ancestors of", "previous", "current", "next") | |||
if filters_config: | |||
additional_operators = [] | |||
for key in filters_config: | |||
additional_operators.append(key.lower()) | |||
valid_operators = tuple(set(valid_operators + tuple(additional_operators))) | |||
if f.operator.lower() not in valid_operators: | |||
frappe.throw(frappe._("Operator must be one of {0}").format(", ".join(valid_operators))) | |||