summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui/tablefilter.py
diff options
context:
space:
mode:
authorElliot Smith <elliot.smith@intel.com>2016-01-15 13:00:54 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-01-15 16:30:00 +0000
commit33b011c1589519db8176c9f5a4abb540698902e6 (patch)
tree104367160098dffb4c05c2120db1c2c8ef470449 /bitbake/lib/toaster/toastergui/tablefilter.py
parentf8d383d87f0b9d4a4c9ae7b1a6c8ceebf90ef9b0 (diff)
downloadpoky-33b011c1589519db8176c9f5a4abb540698902e6.tar.gz
bitbake: toastergui: implement "today" and "yesterday" filters
Add the "today" and "yesterday" filters to the started_on and completed_on columns in the builds table. During this work, some minor adjustments were made to the behaviour of the builds table: * Amend filter action variable names so they're more succinct. * Retain order in which actions are added to a filter, as this ordering is used in the UI when displaying the filter actions. * Always show the table chrome, otherwise it's not possible to edit the columns shown until there are 10 or more results. * Because date range searches may return no results, make sure that the search bar and "show all results" link are visible when the query returns no results. [YOCTO #8738] (Bitbake rev: f17cfa009e58833e0e55884fa04de8abd522b6bc) Signed-off-by: Elliot Smith <elliot.smith@intel.com> Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastergui/tablefilter.py')
-rw-r--r--bitbake/lib/toaster/toastergui/tablefilter.py140
1 files changed, 116 insertions, 24 deletions
diff --git a/bitbake/lib/toaster/toastergui/tablefilter.py b/bitbake/lib/toaster/toastergui/tablefilter.py
index 1ea30da304..bd8decd0e3 100644
--- a/bitbake/lib/toaster/toastergui/tablefilter.py
+++ b/bitbake/lib/toaster/toastergui/tablefilter.py
@@ -18,13 +18,18 @@
18# You should have received a copy of the GNU General Public License along 18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc., 19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
21from django.db.models import Q, Max, Min 22from django.db.models import Q, Max, Min
22from django.utils import dateparse, timezone 23from django.utils import dateparse, timezone
24from datetime import timedelta
25from querysetfilter import QuerysetFilter
23 26
24class TableFilter(object): 27class TableFilter(object):
25 """ 28 """
26 Stores a filter for a named field, and can retrieve the action 29 Stores a filter for a named field, and can retrieve the action
27 requested from the set of actions for that filter 30 requested from the set of actions for that filter;
31 the order in which actions are added governs the order in which they
32 are returned in the JSON for the filter
28 """ 33 """
29 34
30 def __init__(self, name, title): 35 def __init__(self, name, title):
@@ -32,7 +37,11 @@ class TableFilter(object):
32 self.title = title 37 self.title = title
33 self.__filter_action_map = {} 38 self.__filter_action_map = {}
34 39
40 # retains the ordering of actions
41 self.__filter_action_keys = []
42
35 def add_action(self, action): 43 def add_action(self, action):
44 self.__filter_action_keys.append(action.name)
36 self.__filter_action_map[action.name] = action 45 self.__filter_action_map[action.name] = action
37 46
38 def get_action(self, action_name): 47 def get_action(self, action_name):
@@ -56,7 +65,8 @@ class TableFilter(object):
56 }) 65 })
57 66
58 # add other filter actions 67 # add other filter actions
59 for action_name, filter_action in self.__filter_action_map.iteritems(): 68 for action_name in self.__filter_action_keys:
69 filter_action = self.__filter_action_map[action_name]
60 obj = filter_action.to_json(queryset) 70 obj = filter_action.to_json(queryset)
61 obj['action_name'] = action_name 71 obj['action_name'] = action_name
62 filter_actions.append(obj) 72 filter_actions.append(obj)
@@ -67,6 +77,40 @@ class TableFilter(object):
67 'filter_actions': filter_actions 77 'filter_actions': filter_actions
68 } 78 }
69 79
80class TableFilterQueryHelper(object):
81 def dateStringsToQ(self, field_name, date_from_str, date_to_str):
82 """
83 Convert the date strings from_date_str and to_date_str into a
84 set of args in the form
85
86 {'<field_name>__gte': <date from>, '<field_name>__lte': <date to>}
87
88 where date_from and date_to are Django-timezone-aware dates; then
89 convert that into a Django Q object
90
91 Returns the Q object based on those criteria
92 """
93
94 # one of the values required for the filter is missing, so set
95 # it to the one which was supplied
96 if date_from_str == '':
97 date_from_str = date_to_str
98 elif date_to_str == '':
99 date_to_str = date_from_str
100
101 date_from_naive = dateparse.parse_datetime(date_from_str + ' 00:00:00')
102 date_to_naive = dateparse.parse_datetime(date_to_str + ' 23:59:59')
103
104 tz = timezone.get_default_timezone()
105 date_from = timezone.make_aware(date_from_naive, tz)
106 date_to = timezone.make_aware(date_to_naive, tz)
107
108 args = {}
109 args[field_name + '__gte'] = date_from
110 args[field_name + '__lte'] = date_to
111
112 return Q(**args)
113
70class TableFilterAction(object): 114class TableFilterAction(object):
71 """ 115 """
72 A filter action which displays in the filter popup for a ToasterTable 116 A filter action which displays in the filter popup for a ToasterTable
@@ -99,7 +143,7 @@ class TableFilterAction(object):
99 return { 143 return {
100 'title': self.title, 144 'title': self.title,
101 'type': self.type, 145 'type': self.type,
102 'count': self.queryset_filter.count(queryset) 146 'count': self.filter(queryset).count()
103 } 147 }
104 148
105class TableFilterActionToggle(TableFilterAction): 149class TableFilterActionToggle(TableFilterAction):
@@ -113,15 +157,70 @@ class TableFilterActionToggle(TableFilterAction):
113 super(TableFilterActionToggle, self).__init__(*args) 157 super(TableFilterActionToggle, self).__init__(*args)
114 self.type = 'toggle' 158 self.type = 'toggle'
115 159
160class TableFilterActionDay(TableFilterAction):
161 """
162 A filter action which filters according to the named datetime field and a
163 string representing a day ("today" or "yesterday")
164 """
165
166 TODAY = 'today'
167 YESTERDAY = 'yesterday'
168
169 def __init__(self, name, title, field, day,
170 queryset_filter = QuerysetFilter(), query_helper = TableFilterQueryHelper()):
171 """
172 field: (string) the datetime field to filter by
173 day: (string) "today" or "yesterday"
174 """
175 super(TableFilterActionDay, self).__init__(
176 name,
177 title,
178 queryset_filter
179 )
180 self.type = 'day'
181 self.field = field
182 self.day = day
183 self.query_helper = query_helper
184
185 def filter(self, queryset):
186 """
187 Apply the day filtering before returning the queryset;
188 this is done here as the value of the filter criteria changes
189 depending on when the filtering is applied
190 """
191
192 criteria = None
193 date_str = None
194 now = timezone.now()
195
196 if self.day == self.YESTERDAY:
197 increment = timedelta(days=1)
198 wanted_date = now - increment
199 else:
200 wanted_date = now
201
202 wanted_date_str = wanted_date.strftime('%Y-%m-%d')
203
204 criteria = self.query_helper.dateStringsToQ(
205 self.field,
206 wanted_date_str,
207 wanted_date_str
208 )
209
210 self.queryset_filter.set_criteria(criteria)
211
212 return self.queryset_filter.filter(queryset)
213
116class TableFilterActionDateRange(TableFilterAction): 214class TableFilterActionDateRange(TableFilterAction):
117 """ 215 """
118 A filter action which will filter the queryset by a date range. 216 A filter action which will filter the queryset by a date range.
119 The date range can be set via set_params() 217 The date range can be set via set_params()
120 """ 218 """
121 219
122 def __init__(self, name, title, field, queryset_filter): 220 def __init__(self, name, title, field,
221 queryset_filter = QuerysetFilter(), query_helper = TableFilterQueryHelper()):
123 """ 222 """
124 field: the field to find the max/min range from in the queryset 223 field: (string) the field to find the max/min range from in the queryset
125 """ 224 """
126 super(TableFilterActionDateRange, self).__init__( 225 super(TableFilterActionDateRange, self).__init__(
127 name, 226 name,
@@ -131,9 +230,13 @@ class TableFilterActionDateRange(TableFilterAction):
131 230
132 self.type = 'daterange' 231 self.type = 'daterange'
133 self.field = field 232 self.field = field
233 self.query_helper = query_helper
134 234
135 def set_filter_params(self, params): 235 def set_filter_params(self, params):
136 """ 236 """
237 This filter depends on the user selecting some input, so it needs
238 to have its parameters set before its queryset is filtered
239
137 params: (str) a string of extra parameters for the filtering 240 params: (str) a string of extra parameters for the filtering
138 in the format "2015-12-09,2015-12-11" (from,to); this is passed in the 241 in the format "2015-12-09,2015-12-11" (from,to); this is passed in the
139 querystring and used to set the criteria on the QuerysetFilter 242 querystring and used to set the criteria on the QuerysetFilter
@@ -143,30 +246,18 @@ class TableFilterActionDateRange(TableFilterAction):
143 # if params are invalid, return immediately, resetting criteria 246 # if params are invalid, return immediately, resetting criteria
144 # on the QuerysetFilter 247 # on the QuerysetFilter
145 try: 248 try:
146 from_date_str, to_date_str = params.split(',') 249 date_from_str, date_to_str = params.split(',')
147 except ValueError: 250 except ValueError:
148 self.queryset_filter.set_criteria(None) 251 self.queryset_filter.set_criteria(None)
149 return 252 return
150 253
151 # one of the values required for the filter is missing, so set 254 # one of the values required for the filter is missing, so set
152 # it to the one which was supplied 255 # it to the one which was supplied
153 if from_date_str == '': 256 criteria = self.query_helper.dateStringsToQ(
154 from_date_str = to_date_str 257 self.field,
155 elif to_date_str == '': 258 date_from_str,
156 to_date_str = from_date_str 259 date_to_str
157 260 )
158 date_from_naive = dateparse.parse_datetime(from_date_str + ' 00:00:00')
159 date_to_naive = dateparse.parse_datetime(to_date_str + ' 23:59:59')
160
161 tz = timezone.get_default_timezone()
162 date_from = timezone.make_aware(date_from_naive, tz)
163 date_to = timezone.make_aware(date_to_naive, tz)
164
165 args = {}
166 args[self.field + '__gte'] = date_from
167 args[self.field + '__lte'] = date_to
168
169 criteria = Q(**args)
170 self.queryset_filter.set_criteria(criteria) 261 self.queryset_filter.set_criteria(criteria)
171 262
172 def to_json(self, queryset): 263 def to_json(self, queryset):
@@ -179,7 +270,8 @@ class TableFilterActionDateRange(TableFilterAction):
179 data['max'] = queryset.aggregate(Max(self.field))[self.field + '__max'] 270 data['max'] = queryset.aggregate(Max(self.field))[self.field + '__max']
180 271
181 # a range filter has a count of None, as the number of records it 272 # a range filter has a count of None, as the number of records it
182 # will select depends on the date range entered 273 # will select depends on the date range entered and we don't know
274 # that ahead of time
183 data['count'] = None 275 data['count'] = None
184 276
185 return data 277 return data