summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Wood <michael.g.wood@intel.com>2016-05-16 14:50:40 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-05-17 14:43:30 +0100
commit54bf7cce48547289489203812f2e01cb755f0db4 (patch)
treeb744123fed2c7e15ab4d1a45c1dce988d3dd4a58
parenta906a09c730683ee14b84fd890d109f52c9e3b02 (diff)
downloadpoky-54bf7cce48547289489203812f2e01cb755f0db4.tar.gz
bitbake: toaster: toastertables: Clean up and fix up a number of items
- Remove the unused 'computation' field - Remove the code to try to make the tables behave like an api - Remove custom JSON encoder in favour of DjangoJSONEncoder - Simplify get_data and add comments - Add exception type instead of using generic Exception - Clean up python style warnings (Bitbake rev: 16d8198e8f6668c5fa5467ff4bda86c5d66a6cad) Signed-off-by: Michael Wood <michael.g.wood@intel.com> Signed-off-by: Elliot Smith <elliot.smith@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/table.js21
-rw-r--r--bitbake/lib/toaster/toastergui/tables.py11
-rw-r--r--bitbake/lib/toaster/toastergui/widgets.py127
3 files changed, 72 insertions, 87 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/table.js b/bitbake/lib/toaster/toastergui/static/js/table.js
index f738144ae5..7f76f555fc 100644
--- a/bitbake/lib/toaster/toastergui/static/js/table.js
+++ b/bitbake/lib/toaster/toastergui/static/js/table.js
@@ -101,27 +101,8 @@ function tableInit(ctx){
101 var row = $("<tr></tr>"); 101 var row = $("<tr></tr>");
102 column_index = -1; 102 column_index = -1;
103 for (var key_j in tableData.rows[i]){ 103 for (var key_j in tableData.rows[i]){
104
105 /* if we have a static: version of a key, prefer the static: version for rendering */
106 var orig_key_j = key_j;
107
108 if (key_j.indexOf("static:") === 0) {
109 if (key_j.substr("static:".length) in tableData.rows[i]) {
110 continue;
111 }
112 orig_key_j = key_j.substr("static:".length)
113 } else if (("static:" + key_j) in tableData.rows[i]) {
114 key_j = "static:" + key_j;
115 }
116
117 /* we skip over un-displayable column entries */
118 column_index += 1;
119 if (! tableData.columns[column_index].displayable) {
120 continue;
121 }
122
123 var td = $("<td></td>"); 104 var td = $("<td></td>");
124 td.prop("class", orig_key_j); 105 td.prop("class", key_j);
125 if (tableData.rows[i][key_j]){ 106 if (tableData.rows[i][key_j]){
126 td.html(tableData.rows[i][key_j]); 107 td.html(tableData.rows[i][key_j]);
127 } 108 }
diff --git a/bitbake/lib/toaster/toastergui/tables.py b/bitbake/lib/toaster/toastergui/tables.py
index d375da434f..d21bed1fbe 100644
--- a/bitbake/lib/toaster/toastergui/tables.py
+++ b/bitbake/lib/toaster/toastergui/tables.py
@@ -190,17 +190,6 @@ class LayersTable(ToasterTable):
190 static_data_name="add-del-layers", 190 static_data_name="add-del-layers",
191 static_data_template='{% include "layer_btn.html" %}') 191 static_data_template='{% include "layer_btn.html" %}')
192 192
193 project = Project.objects.get(pk=kwargs['pid'])
194 self.add_column(title="LayerDetailsUrl",
195 displayable = False,
196 field_name="layerdetailurl",
197 computation = lambda x: reverse('layerdetails', args=(project.id, x.id)))
198
199 self.add_column(title="name",
200 displayable = False,
201 field_name="name",
202 computation = lambda x: x.layer.name)
203
204 193
205class MachinesTable(ToasterTable): 194class MachinesTable(ToasterTable):
206 """Table of Machines in Toaster""" 195 """Table of Machines in Toaster"""
diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py
index d2ef5d3dba..4117031830 100644
--- a/bitbake/lib/toaster/toastergui/widgets.py
+++ b/bitbake/lib/toaster/toastergui/widgets.py
@@ -43,9 +43,12 @@ import urllib
43import logging 43import logging
44logger = logging.getLogger("toaster") 44logger = logging.getLogger("toaster")
45 45
46from toastergui.views import objtojson
47from toastergui.tablefilter import TableFilterMap 46from toastergui.tablefilter import TableFilterMap
48 47
48
49class NoFieldOrDataNme(Exception):
50 pass
51
49class ToasterTable(TemplateView): 52class ToasterTable(TemplateView):
50 def __init__(self, *args, **kwargs): 53 def __init__(self, *args, **kwargs):
51 super(ToasterTable, self).__init__() 54 super(ToasterTable, self).__init__()
@@ -63,25 +66,19 @@ class ToasterTable(TemplateView):
63 self.empty_state = "Sorry - no data found" 66 self.empty_state = "Sorry - no data found"
64 self.default_orderby = "" 67 self.default_orderby = ""
65 68
66 # add the "id" column, undisplayable, by default
67 self.add_column(title="Id",
68 displayable=False,
69 orderable=True,
70 field_name="id")
71
72 # prevent HTTP caching of table data 69 # prevent HTTP caching of table data
73 @cache_control(must_revalidate=True, max_age=0, no_store=True, no_cache=True) 70 @cache_control(must_revalidate=True,
71 max_age=0, no_store=True, no_cache=True)
74 def dispatch(self, *args, **kwargs): 72 def dispatch(self, *args, **kwargs):
75 return super(ToasterTable, self).dispatch(*args, **kwargs) 73 return super(ToasterTable, self).dispatch(*args, **kwargs)
76 74
77 def get_context_data(self, **kwargs): 75 def get_context_data(self, **kwargs):
78 context = super(ToasterTable, self).get_context_data(**kwargs) 76 context = super(ToasterTable, self).get_context_data(**kwargs)
79 context['title'] = self.title 77 context['title'] = self.title
80 context['table_name'] = type(self).__name__.lower() 78 context['table_name'] = type(self).__name__.lower()
81 79
82 return context 80 return context
83 81
84
85 def get(self, request, *args, **kwargs): 82 def get(self, request, *args, **kwargs):
86 if request.GET.get('format', None) == 'json': 83 if request.GET.get('format', None) == 'json':
87 84
@@ -102,8 +99,6 @@ class ToasterTable(TemplateView):
102 return super(ToasterTable, self).get(request, *args, **kwargs) 99 return super(ToasterTable, self).get(request, *args, **kwargs)
103 100
104 def get_filter_info(self, request, **kwargs): 101 def get_filter_info(self, request, **kwargs):
105 data = None
106
107 self.setup_filters(**kwargs) 102 self.setup_filters(**kwargs)
108 103
109 search = request.GET.get("search", None) 104 search = request.GET.get("search", None)
@@ -117,13 +112,18 @@ class ToasterTable(TemplateView):
117 cls=DjangoJSONEncoder) 112 cls=DjangoJSONEncoder)
118 113
119 def setup_columns(self, *args, **kwargs): 114 def setup_columns(self, *args, **kwargs):
120 """ function to implement in the subclass which sets up the columns """ 115 """ function to implement in the subclass which sets up
116 the columns """
121 pass 117 pass
118
122 def setup_filters(self, *args, **kwargs): 119 def setup_filters(self, *args, **kwargs):
123 """ function to implement in the subclass which sets up the filters """ 120 """ function to implement in the subclass which sets up the
121 filters """
124 pass 122 pass
123
125 def setup_queryset(self, *args, **kwargs): 124 def setup_queryset(self, *args, **kwargs):
126 """ function to implement in the subclass which sets up the queryset""" 125 """ function to implement in the subclass which sets up the
126 queryset"""
127 pass 127 pass
128 128
129 def add_filter(self, table_filter): 129 def add_filter(self, table_filter):
@@ -137,7 +137,6 @@ class ToasterTable(TemplateView):
137 def add_column(self, title="", help_text="", 137 def add_column(self, title="", help_text="",
138 orderable=False, hideable=True, hidden=False, 138 orderable=False, hideable=True, hidden=False,
139 field_name="", filter_name=None, static_data_name=None, 139 field_name="", filter_name=None, static_data_name=None,
140 displayable=True, computation=None,
141 static_data_template=None): 140 static_data_template=None):
142 """Add a column to the table. 141 """Add a column to the table.
143 142
@@ -155,18 +154,15 @@ class ToasterTable(TemplateView):
155 as data 154 as data
156 """ 155 """
157 156
158 self.columns.append({'title' : title, 157 self.columns.append({'title': title,
159 'help_text' : help_text, 158 'help_text': help_text,
160 'orderable' : orderable, 159 'orderable': orderable,
161 'hideable' : hideable, 160 'hideable': hideable,
162 'hidden' : hidden, 161 'hidden': hidden,
163 'field_name' : field_name, 162 'field_name': field_name,
164 'filter_name' : filter_name, 163 'filter_name': filter_name,
165 'static_data_name': static_data_name, 164 'static_data_name': static_data_name,
166 'static_data_template': static_data_template, 165 'static_data_template': static_data_template})
167 'displayable': displayable,
168 'computation': computation,
169 })
170 166
171 def set_column_hidden(self, title, hidden): 167 def set_column_hidden(self, title, hidden):
172 """ 168 """
@@ -190,8 +186,8 @@ class ToasterTable(TemplateView):
190 """Utility function to render the static data template""" 186 """Utility function to render the static data template"""
191 187
192 context = { 188 context = {
193 'extra' : self.static_context_extra, 189 'extra': self.static_context_extra,
194 'data' : row, 190 'data': row,
195 } 191 }
196 192
197 context = Context(context) 193 context = Context(context)
@@ -241,7 +237,7 @@ class ToasterTable(TemplateView):
241 237
242 if not hasattr(self.queryset.model, 'search_allowed_fields'): 238 if not hasattr(self.queryset.model, 'search_allowed_fields'):
243 raise Exception("Search fields aren't defined in the model %s" 239 raise Exception("Search fields aren't defined in the model %s"
244 % self.queryset.model) 240 % self.queryset.model)
245 241
246 search_queries = [] 242 search_queries = []
247 for st in search_term.split(" "): 243 for st in search_term.split(" "):
@@ -254,7 +250,6 @@ class ToasterTable(TemplateView):
254 250
255 self.queryset = self.queryset.filter(search_queries) 251 self.queryset = self.queryset.filter(search_queries)
256 252
257
258 def get_data(self, request, **kwargs): 253 def get_data(self, request, **kwargs):
259 """ 254 """
260 Returns the data for the page requested with the specified 255 Returns the data for the page requested with the specified
@@ -262,7 +257,8 @@ class ToasterTable(TemplateView):
262 257
263 filters: filter and action name, e.g. "outcome:build_succeeded" 258 filters: filter and action name, e.g. "outcome:build_succeeded"
264 filter_value: value to pass to the named filter+action, e.g. "on" 259 filter_value: value to pass to the named filter+action, e.g. "on"
265 (for a toggle filter) or "2015-12-11,2015-12-12" (for a date range filter) 260 (for a toggle filter) or "2015-12-11,2015-12-12"
261 (for a date range filter)
266 """ 262 """
267 263
268 page_num = request.GET.get("page", 1) 264 page_num = request.GET.get("page", 1)
@@ -313,16 +309,16 @@ class ToasterTable(TemplateView):
313 page = paginator.page(1) 309 page = paginator.page(1)
314 310
315 data = { 311 data = {
316 'total' : self.queryset.count(), 312 'total': self.queryset.count(),
317 'default_orderby' : self.default_orderby, 313 'default_orderby': self.default_orderby,
318 'columns' : self.columns, 314 'columns': self.columns,
319 'rows' : [], 315 'rows': [],
320 'error' : "ok", 316 'error': "ok",
321 } 317 }
322 318
323 try: 319 try:
324 for row in page.object_list: 320 for model_obj in page.object_list:
325 #Use collection to maintain the order 321 # Use collection to maintain the order
326 required_data = collections.OrderedDict() 322 required_data = collections.OrderedDict()
327 323
328 for col in self.columns: 324 for col in self.columns:
@@ -330,38 +326,57 @@ class ToasterTable(TemplateView):
330 if not field: 326 if not field:
331 field = col['static_data_name'] 327 field = col['static_data_name']
332 if not field: 328 if not field:
333 raise Exception("Must supply a field_name or static_data_name for column %s.%s" % (self.__class__.__name__,col)) 329 raise NoFieldOrDataNme("Must supply a field_name or"
330 "static_data_name for column"
331 "%s.%s" %
332 (self.__class__.__name__, col))
333
334 # Check if we need to process some static data 334 # Check if we need to process some static data
335 if "static_data_name" in col and col['static_data_name']: 335 if "static_data_name" in col and col['static_data_name']:
336 required_data["static:%s" % col['static_data_name']] = self.render_static_data(col['static_data_template'], row)
337
338 # Overwrite the field_name with static_data_name 336 # Overwrite the field_name with static_data_name
339 # so that this can be used as the html class name 337 # so that this can be used as the html class name
340
341 col['field_name'] = col['static_data_name'] 338 col['field_name'] = col['static_data_name']
342 339
343 # compute the computation on the raw data if needed 340 # Render the template given
344 model_data = row 341 required_data[col['static_data_name']] = \
345 if col['computation']: 342 self.render_static_data(
346 model_data = col['computation'](row) 343 col['static_data_template'], model_obj)
347 else: 344 else:
348 # Traverse to any foriegn key in the object hierachy 345 # Traverse to any foriegn key in the field
349 for subfield in field.split("__"): 346 # e.g. recipe__layer_version__name
350 if hasattr(model_data, subfield): 347 model_data = None
351 model_data = getattr(model_data, subfield) 348
352 # The field could be a function on the model so check 349 if "__" in field:
353 # If it is then call it 350 for subfield in field.split("__"):
351 if not model_data:
352 # The first iteration is always going to
353 # be on the actual model object instance.
354 # Subsequent ones are on the result of
355 # that. e.g. forieng key objects
356 model_data = getattr(model_obj,
357 subfield)
358 else:
359 model_data = getattr(model_data,
360 subfield)
361
362 else:
363 model_data = getattr(model_obj,
364 col['field_name'])
365
366 # We might have a model function as the field so
367 # call it to return the data needed
354 if isinstance(model_data, types.MethodType): 368 if isinstance(model_data, types.MethodType):
355 model_data = model_data() 369 model_data = model_data()
356 370
357 required_data[col['field_name']] = model_data 371 required_data[col['field_name']] = model_data
358 372
359 data['rows'].append(required_data) 373 data['rows'].append(required_data)
360 374
361 except FieldError: 375 except FieldError:
362 # pass it to the user - programming-error here 376 # pass it to the user - programming-error here
363 raise 377 raise
364 data = json.dumps(data, indent=2, default=objtojson) 378
379 data = json.dumps(data, indent=2, cls=DjangoJSONEncoder)
365 cache.set(cache_name, data, 60*30) 380 cache.set(cache_name, data, 60*30)
366 381
367 return data 382 return data