diff --git a/tailbone/grids/filters.py b/tailbone/grids/filters.py
index 0014c750..3a497d13 100644
--- a/tailbone/grids/filters.py
+++ b/tailbone/grids/filters.py
@@ -553,6 +553,7 @@ class AlchemyDateFilter(AlchemyGridFilter):
'greater_equal': "on or after",
'less_than': "before",
'less_equal': "on or before",
+ 'between': "between",
'is_null': "is null",
'is_not_null': "is not null",
'is_any': "is any",
@@ -562,8 +563,18 @@ class AlchemyDateFilter(AlchemyGridFilter):
"""
Expose greater-than / less-than verbs in addition to core.
"""
- return ['equal', 'not_equal', 'greater_than', 'greater_equal',
- 'less_than', 'less_equal', 'is_null', 'is_not_null', 'is_any']
+ return [
+ 'equal',
+ 'not_equal',
+ 'greater_than',
+ 'greater_equal',
+ 'less_than',
+ 'less_equal',
+ 'between',
+ 'is_null',
+ 'is_not_null',
+ 'is_any',
+ ]
def make_date(self, value):
"""
@@ -577,6 +588,44 @@ class AlchemyDateFilter(AlchemyGridFilter):
else:
return dt.date()
+ def filter_between(self, query, value):
+ """
+ Filter data with a "between" query. Really this uses ">=" and "<="
+ (inclusive) logic instead of SQL "between" keyword.
+ """
+ if value is None or value == '':
+ return query
+
+ if '|' not in value:
+ return query
+
+ values = value.split('|')
+ if len(values) != 2:
+ return query
+
+ start_date, end_date = values
+ if start_date:
+ start_date = self.make_date(start_date)
+ if end_date:
+ end_date = self.make_date(end_date)
+
+ # we'll only filter if we have start and/or end date
+ if not start_date and not end_date:
+ return query
+
+ return self.filter_date_range(query, start_date, end_date)
+
+ def filter_date_range(self, query, start_date, end_date):
+ """
+ This method should actually apply filter(s) to the query, according to
+ the given date range. Subclasses may override this logic.
+ """
+ if start_date:
+ query = query.filter(self.column >= start_date)
+ if end_date:
+ query = query.filter(self.column <= end_date)
+ return query
+
class AlchemyDateTimeFilter(AlchemyDateFilter):
"""
@@ -666,6 +715,17 @@ class AlchemyDateTimeFilter(AlchemyDateFilter):
time = make_utc(localtime(self.config, time))
return query.filter(self.column < time)
+ def filter_date_range(self, query, start_date, end_date):
+ if start_date:
+ start_time = datetime.datetime.combine(start_date, datetime.time(0))
+ start_time = localtime(self.config, start_time)
+ query = query.filter(self.column >= make_utc(start_time))
+ if end_date:
+ end_time = datetime.datetime.combine(end_date + datetime.timedelta(days=1), datetime.time(0))
+ end_time = localtime(self.config, end_time)
+ query = query.filter(self.column <= make_utc(end_time))
+ return query
+
class AlchemyLocalDateTimeFilter(AlchemyDateTimeFilter):
"""
@@ -756,6 +816,17 @@ class AlchemyLocalDateTimeFilter(AlchemyDateTimeFilter):
time = localtime(self.config, time, tzinfo=False)
return query.filter(self.column < time)
+ def filter_date_range(self, query, start_date, end_date):
+ if start_date:
+ start_time = datetime.datetime.combine(start_date, datetime.time(0))
+ start_time = localtime(self.config, start_time, tzinfo=False)
+ query = query.filter(self.column >= start_time)
+ if end_date:
+ end_time = datetime.datetime.combine(end_date + datetime.timedelta(days=1), datetime.time(0))
+ end_time = localtime(self.config, end_time, tzinfo=False)
+ query = query.filter(self.column <= end_time)
+ return query
+
class AlchemyGPCFilter(AlchemyGridFilter):
"""
diff --git a/tailbone/static/js/tailbone.buefy.datepicker.js b/tailbone/static/js/tailbone.buefy.datepicker.js
index 5cc620bf..fe649380 100644
--- a/tailbone/static/js/tailbone.buefy.datepicker.js
+++ b/tailbone/static/js/tailbone.buefy.datepicker.js
@@ -14,6 +14,7 @@ const TailboneDatepicker = {
':value="value ? parseDate(value) : null"',
'@input="dateChanged"',
':disabled="disabled"',
+ 'ref="trueDatePicker"',
'>',
''
].join(' '),
@@ -49,7 +50,11 @@ const TailboneDatepicker = {
dateChanged(date) {
this.$emit('input', this.formatDate(date))
- }
+ },
+
+ focus() {
+ this.$refs.trueDatePicker.focus()
+ },
}
}
diff --git a/tailbone/static/js/tailbone.buefy.grid.js b/tailbone/static/js/tailbone.buefy.grid.js
index ee873c6d..8af8b5b0 100644
--- a/tailbone/static/js/tailbone.buefy.grid.js
+++ b/tailbone/static/js/tailbone.buefy.grid.js
@@ -1,4 +1,53 @@
+const GridFilterDateValue = {
+ template: '#grid-filter-date-value-template',
+ props: {
+ value: String,
+ dateRange: Boolean,
+ },
+ data() {
+ return {
+ startDate: null,
+ endDate: null,
+ }
+ },
+ mounted() {
+ if (this.dateRange) {
+ if (this.value.includes('|')) {
+ let values = this.value.split('|')
+ if (values.length == 2) {
+ this.startDate = values[0]
+ this.endDate = values[1]
+ } else {
+ this.startDate = this.value
+ }
+ } else {
+ this.startDate = this.value
+ }
+ } else {
+ this.startDate = this.value
+ }
+ },
+ methods: {
+ focus() {
+ this.$refs.startDate.focus()
+ },
+ startDateChanged(value) {
+ if (this.dateRange) {
+ value += '|' + this.endDate
+ }
+ this.$emit('input', value)
+ },
+ endDateChanged(value) {
+ value = this.startDate + '|' + value
+ this.$emit('input', value)
+ },
+ },
+}
+
+Vue.component('grid-filter-date-value', GridFilterDateValue)
+
+
const GridFilter = {
template: '#grid-filter-template',
props: {
@@ -14,6 +63,23 @@ const GridFilter = {
})
},
+ valuedVerb() {
+ /* this returns true if the filter's current verb should expose value input(s) */
+
+ // if filter has no "valueless" verbs, then all verbs should expose value inputs
+ if (!this.filter.valueless_verbs) {
+ return true
+ }
+
+ // if filter *does* have valueless verbs, check if "current" verb is valueless
+ if (this.filter.valueless_verbs.includes(this.filter.verb)) {
+ return false
+ }
+
+ // current verb is *not* valueless
+ return true
+ },
+
focusValue: function() {
this.$refs.valueInput.focus()
// this.$refs.valueInput.select()
diff --git a/tailbone/templates/grids/buefy.mako b/tailbone/templates/grids/buefy.mako
index 9fcf5f9b..39feedd5 100644
--- a/tailbone/templates/grids/buefy.mako
+++ b/tailbone/templates/grids/buefy.mako
@@ -1,5 +1,29 @@
## -*- coding: utf-8; -*-
+
+