diff options
| -rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/table.js | 14 | ||||
| -rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 31 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/widgets.py | 16 |
3 files changed, 54 insertions, 7 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/table.js b/bitbake/lib/toaster/toastergui/static/js/table.js index 7588a4ab9a..80e9ec2392 100644 --- a/bitbake/lib/toaster/toastergui/static/js/table.js +++ b/bitbake/lib/toaster/toastergui/static/js/table.js | |||
| @@ -113,8 +113,20 @@ function tableInit(ctx){ | |||
| 113 | for (var i in tableData.rows){ | 113 | for (var i in tableData.rows){ |
| 114 | var row = $("<tr></tr>"); | 114 | var row = $("<tr></tr>"); |
| 115 | for (var key_j in tableData.rows[i]){ | 115 | for (var key_j in tableData.rows[i]){ |
| 116 | /* if we have a static: version of a key, prefer the static: version for rendering */ | ||
| 117 | var orig_key_j = key_j; | ||
| 118 | |||
| 119 | if (key_j.indexOf("static:") === 0) { | ||
| 120 | if (key_j.substr("static:".length) in tableData.rows[i]) { | ||
| 121 | continue; | ||
| 122 | } | ||
| 123 | orig_key_j = key_j.substr("static:".length) | ||
| 124 | } else if (("static:" + key_j) in tableData.rows[i]) { | ||
| 125 | key_j = "static:" + key_j; | ||
| 126 | } | ||
| 127 | |||
| 116 | var td = $("<td></td>"); | 128 | var td = $("<td></td>"); |
| 117 | td.prop("class", key_j); | 129 | td.prop("class", orig_key_j); |
| 118 | if (tableData.rows[i][key_j]){ | 130 | if (tableData.rows[i][key_j]){ |
| 119 | td.html(tableData.rows[i][key_j]); | 131 | td.html(tableData.rows[i][key_j]); |
| 120 | } | 132 | } |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 91c4fa2543..280159ad2c 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -87,6 +87,35 @@ def _project_recent_build_list(prj): | |||
| 87 | list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3])) | 87 | list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3])) |
| 88 | 88 | ||
| 89 | 89 | ||
| 90 | |||
| 91 | def objtojson(obj): | ||
| 92 | from django.db.models.query import QuerySet | ||
| 93 | from django.db.models import Model, IntegerField | ||
| 94 | from django.db.models.fields.related import ForeignKey | ||
| 95 | |||
| 96 | if isinstance(obj, datetime): | ||
| 97 | return obj.isoformat() | ||
| 98 | elif isinstance(obj, timedelta): | ||
| 99 | return obj.total_seconds() | ||
| 100 | elif isinstance(obj, QuerySet) or isinstance(obj, set): | ||
| 101 | return list(obj) | ||
| 102 | elif type(obj).__name__ == "RelatedManager": | ||
| 103 | return [x.pk for x in obj.all()] | ||
| 104 | elif hasattr( obj, '__dict__') and isinstance(obj, Model): | ||
| 105 | d = obj.__dict__ | ||
| 106 | nd = dict(d) | ||
| 107 | for di in d.keys(): | ||
| 108 | if di.startswith("_"): | ||
| 109 | del nd[di] | ||
| 110 | elif isinstance(d[di], Model): | ||
| 111 | nd[di] = d[di].pk | ||
| 112 | elif isinstance(d[di], int) and hasattr(obj, "get_%s_display" % di): | ||
| 113 | nd[di] = getattr(obj, "get_%s_display" % di)() | ||
| 114 | return nd | ||
| 115 | else: | ||
| 116 | raise TypeError("Unserializable object %s (%s) of type %s" % ( obj, dir(obj), type(obj))) | ||
| 117 | |||
| 118 | |||
| 90 | def _template_renderer(template): | 119 | def _template_renderer(template): |
| 91 | def func_wrapper(view): | 120 | def func_wrapper(view): |
| 92 | def returned_wrapper(request, *args, **kwargs): | 121 | def returned_wrapper(request, *args, **kwargs): |
| @@ -127,7 +156,7 @@ def _template_renderer(template): | |||
| 127 | else: | 156 | else: |
| 128 | raise TypeError("Unserializable object %s of type %s" % ( obj, type(obj))) | 157 | raise TypeError("Unserializable object %s of type %s" % ( obj, type(obj))) |
| 129 | 158 | ||
| 130 | return HttpResponse(jsonfilter(context, default=_objtojson ), | 159 | return HttpResponse(jsonfilter(context, default=objtojson ), |
| 131 | content_type = "application/json; charset=utf-8") | 160 | content_type = "application/json; charset=utf-8") |
| 132 | else: | 161 | else: |
| 133 | return render(request, template, context) | 162 | return render(request, template, context) |
diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py index 4347a3f081..82b7514bd8 100644 --- a/bitbake/lib/toaster/toastergui/widgets.py +++ b/bitbake/lib/toaster/toastergui/widgets.py | |||
| @@ -37,6 +37,7 @@ import json | |||
| 37 | import collections | 37 | import collections |
| 38 | import operator | 38 | import operator |
| 39 | 39 | ||
| 40 | from toastergui.views import objtojson | ||
| 40 | 41 | ||
| 41 | class ToasterTable(TemplateView): | 42 | class ToasterTable(TemplateView): |
| 42 | def __init__(self, *args, **kwargs): | 43 | def __init__(self, *args, **kwargs): |
| @@ -275,19 +276,25 @@ class ToasterTable(TemplateView): | |||
| 275 | 276 | ||
| 276 | for col in self.columns: | 277 | for col in self.columns: |
| 277 | field = col['field_name'] | 278 | field = col['field_name'] |
| 279 | if not field: | ||
| 280 | field = col['static_data_name'] | ||
| 281 | if not field: | ||
| 282 | raise Exception("Must supply a field_name or static_data_name for column %s.%s" % (self.__class__.__name__,col)) | ||
| 278 | # Check if we need to process some static data | 283 | # Check if we need to process some static data |
| 279 | if "static_data_name" in col and col['static_data_name']: | 284 | if "static_data_name" in col and col['static_data_name']: |
| 280 | required_data[col['static_data_name']] = self.render_static_data(col['static_data_template'], row) | 285 | required_data["static:%s" % col['static_data_name']] = self.render_static_data(col['static_data_template'], row) |
| 281 | 286 | ||
| 282 | # Overwrite the field_name with static_data_name | 287 | # Overwrite the field_name with static_data_name |
| 283 | # so that this can be used as the html class name | 288 | # so that this can be used as the html class name |
| 284 | 289 | ||
| 285 | col['field_name'] = col['static_data_name'] | 290 | col['field_name'] = col['static_data_name'] |
| 286 | else: | 291 | |
| 292 | if True: # we add the raw model data at all times | ||
| 287 | model_data = row | 293 | model_data = row |
| 288 | # Traverse to any foriegn key in the object hierachy | 294 | # Traverse to any foriegn key in the object hierachy |
| 289 | for subfield in field.split("__"): | 295 | for subfield in field.split("__"): |
| 290 | model_data = getattr(model_data, subfield) | 296 | if hasattr(model_data, subfield): |
| 297 | model_data = getattr(model_data, subfield) | ||
| 291 | # The field could be a function on the model so check | 298 | # The field could be a function on the model so check |
| 292 | # If it is then call it | 299 | # If it is then call it |
| 293 | if isinstance(model_data, types.MethodType): | 300 | if isinstance(model_data, types.MethodType): |
| @@ -299,8 +306,7 @@ class ToasterTable(TemplateView): | |||
| 299 | 306 | ||
| 300 | except FieldError: | 307 | except FieldError: |
| 301 | print "Error: Requested field does not exist" | 308 | print "Error: Requested field does not exist" |
| 302 | 309 | data = json.dumps(data, indent=2, default=objtojson) | |
| 303 | data = json.dumps(data, indent=2, cls=DjangoJSONEncoder) | ||
| 304 | cache.set(cache_name, data, 60*30) | 310 | cache.set(cache_name, data, 60*30) |
| 305 | 311 | ||
| 306 | return data | 312 | return data |
