Add special "contains any of" verb for string-based grid filters
This commit is contained in:
parent
1420a33649
commit
89f0336af9
|
@ -1044,6 +1044,9 @@ class Grid(object):
|
||||||
valueless = [v for v in filtr.valueless_verbs
|
valueless = [v for v in filtr.valueless_verbs
|
||||||
if v in filtr.verbs]
|
if v in filtr.verbs]
|
||||||
|
|
||||||
|
multiple_values = [v for v in filtr.multiple_value_verbs
|
||||||
|
if v in filtr.verbs]
|
||||||
|
|
||||||
choices = []
|
choices = []
|
||||||
choice_labels = {}
|
choice_labels = {}
|
||||||
if filtr.choices:
|
if filtr.choices:
|
||||||
|
@ -1060,6 +1063,7 @@ class Grid(object):
|
||||||
'visible': filtr.active,
|
'visible': filtr.active,
|
||||||
'verbs': filtr.verbs,
|
'verbs': filtr.verbs,
|
||||||
'valueless_verbs': valueless,
|
'valueless_verbs': valueless,
|
||||||
|
'multiple_value_verbs': multiple_values,
|
||||||
'verb_labels': filtr.verb_labels,
|
'verb_labels': filtr.verb_labels,
|
||||||
'verb': filtr.verb or filtr.default_verb or filtr.verbs[0],
|
'verb': filtr.verb or filtr.default_verb or filtr.verbs[0],
|
||||||
'value': six.text_type(filtr.value) if filtr.value is not None else "",
|
'value': six.text_type(filtr.value) if filtr.value is not None else "",
|
||||||
|
|
|
@ -144,6 +144,7 @@ class GridFilter(object):
|
||||||
'is_empty_or_null': "is either empty or null",
|
'is_empty_or_null': "is either empty or null",
|
||||||
'contains': "contains",
|
'contains': "contains",
|
||||||
'does_not_contain': "does not contain",
|
'does_not_contain': "does not contain",
|
||||||
|
'contains_any_of': "contains any of",
|
||||||
'is_me': "is me",
|
'is_me': "is me",
|
||||||
'is_not_me': "is not me",
|
'is_not_me': "is not me",
|
||||||
}
|
}
|
||||||
|
@ -162,6 +163,10 @@ class GridFilter(object):
|
||||||
'is_not_me',
|
'is_not_me',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
multiple_value_verbs = [
|
||||||
|
'contains_any_of',
|
||||||
|
]
|
||||||
|
|
||||||
value_renderer_factory = DefaultValueRenderer
|
value_renderer_factory = DefaultValueRenderer
|
||||||
data_type = 'string' # default, but will be set from value renderer
|
data_type = 'string' # default, but will be set from value renderer
|
||||||
choices = {}
|
choices = {}
|
||||||
|
@ -382,6 +387,7 @@ class AlchemyStringFilter(AlchemyGridFilter):
|
||||||
Expose contains / does-not-contain verbs in addition to core.
|
Expose contains / does-not-contain verbs in addition to core.
|
||||||
"""
|
"""
|
||||||
return ['contains', 'does_not_contain',
|
return ['contains', 'does_not_contain',
|
||||||
|
'contains_any_of',
|
||||||
'equal', 'not_equal',
|
'equal', 'not_equal',
|
||||||
'is_empty', 'is_not_empty',
|
'is_empty', 'is_not_empty',
|
||||||
'is_null', 'is_not_null',
|
'is_null', 'is_not_null',
|
||||||
|
@ -414,6 +420,39 @@ class AlchemyStringFilter(AlchemyGridFilter):
|
||||||
for v in value.split()]),
|
for v in value.split()]),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
def filter_contains_any_of(self, query, value):
|
||||||
|
"""
|
||||||
|
This filter expects "multiple values" separated by newline character,
|
||||||
|
and will add an "OR" condition with each value being checked via
|
||||||
|
"ILIKE". For instance if the user submits a "value" like this:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
foo bar
|
||||||
|
baz
|
||||||
|
|
||||||
|
This will result in SQL condition like this:
|
||||||
|
|
||||||
|
.. code-block:: sql
|
||||||
|
|
||||||
|
(name ILIKE '%foo%' AND name ILIKE '%bar%') OR name ILIKE '%baz%'
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return query
|
||||||
|
|
||||||
|
values = value.split('\n')
|
||||||
|
values = [value for value in values if value]
|
||||||
|
if not values:
|
||||||
|
return query
|
||||||
|
|
||||||
|
conditions = []
|
||||||
|
for value in values:
|
||||||
|
conditions.append(sa.and_(
|
||||||
|
*[self.column.ilike(self.encode_value('%{}%'.format(v)))
|
||||||
|
for v in value.split()]))
|
||||||
|
|
||||||
|
return query.filter(sa.or_(*conditions))
|
||||||
|
|
||||||
def filter_is_empty(self, query, value):
|
def filter_is_empty(self, query, value):
|
||||||
return query.filter(sa.func.trim(self.column) == self.encode_value(''))
|
return query.filter(sa.func.trim(self.column) == self.encode_value(''))
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,23 @@ const GridFilter = {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
multiValuedVerb() {
|
||||||
|
/* this returns true if the filter's current verb should expose a multi-value input */
|
||||||
|
|
||||||
|
// if filter has no "multi-value" verbs then we safely assume false
|
||||||
|
if (!this.filter.multiple_value_verbs) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// if filter *does* have multi-value verbs, see if "current" is one
|
||||||
|
if (this.filter.multiple_value_verbs.includes(this.filter.verb)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// current verb is not multi-value
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
focusValue: function() {
|
focusValue: function() {
|
||||||
this.$refs.valueInput.focus()
|
this.$refs.valueInput.focus()
|
||||||
// this.$refs.valueInput.select()
|
// this.$refs.valueInput.select()
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
<script type="text/x-template" id="grid-filter-template">
|
<script type="text/x-template" id="grid-filter-template">
|
||||||
|
|
||||||
<div class="level filter" v-show="filter.visible">
|
<div class="level filter" v-show="filter.visible">
|
||||||
<div class="level-left">
|
<div class="level-left"
|
||||||
|
style="align-items: start;">
|
||||||
|
|
||||||
<div class="level-item filter-fieldname">
|
<div class="level-item filter-fieldname">
|
||||||
|
|
||||||
|
@ -40,7 +41,9 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<b-field grouped v-show="filter.active" class="level-item">
|
<b-field grouped v-show="filter.active"
|
||||||
|
class="level-item"
|
||||||
|
style="align-items: start;">
|
||||||
|
|
||||||
<b-select v-model="filter.verb"
|
<b-select v-model="filter.verb"
|
||||||
@input="focusValue()"
|
@input="focusValue()"
|
||||||
|
@ -72,7 +75,14 @@
|
||||||
</option>
|
</option>
|
||||||
</b-select>
|
</b-select>
|
||||||
|
|
||||||
<b-input v-if="filter.data_type == 'string'"
|
<b-input v-if="filter.data_type == 'string' && !multiValuedVerb()"
|
||||||
|
v-model="filter.value"
|
||||||
|
v-show="valuedVerb()"
|
||||||
|
ref="valueInput">
|
||||||
|
</b-input>
|
||||||
|
|
||||||
|
<b-input v-if="filter.data_type == 'string' && multiValuedVerb()"
|
||||||
|
type="textarea"
|
||||||
v-model="filter.value"
|
v-model="filter.value"
|
||||||
v-show="valuedVerb()"
|
v-show="valuedVerb()"
|
||||||
ref="valueInput">
|
ref="valueInput">
|
||||||
|
|
Loading…
Reference in a new issue