diff options
author | Alexandru DAMIAN <alexandru.damian@intel.com> | 2013-12-13 17:14:34 +0000 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2014-01-10 15:20:26 +0000 |
commit | 5482409a370552809de75150350defef04ac7144 (patch) | |
tree | e0af09995517b66cc01be62508fef763907e051d | |
parent | 2251426ae420640c082ec0d0109b9be435075411 (diff) | |
download | poky-5482409a370552809de75150350defef04ac7144.tar.gz |
bitbake: toaster: Build dashboard implementation
This patch adds the build dashboard page implementation,
which is the landing page for the Toaster GUI.
Also adds correct links from the main build page
to the various parts of the dashboard.
[YOCTO #4258]
(Bitbake rev: bf7fbf5c0ee39564d813f82e194242f9d4f73c47)
Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
6 files changed, 125 insertions, 23 deletions
diff --git a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html index 1b037f9539..7d2a1f388e 100644 --- a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html +++ b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html | |||
@@ -3,7 +3,7 @@ | |||
3 | {% block pagecontent %} | 3 | {% block pagecontent %} |
4 | 4 | ||
5 | 5 | ||
6 | <div class="span12"> | 6 | <div class=""> |
7 | <!-- Breadcrumbs --> | 7 | <!-- Breadcrumbs --> |
8 | <div class="section"> | 8 | <div class="section"> |
9 | <ul class="breadcrumb" id="breadcrumb"> | 9 | <ul class="breadcrumb" id="breadcrumb"> |
@@ -40,12 +40,11 @@ | |||
40 | <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li> | 40 | <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li> |
41 | </ul> | 41 | </ul> |
42 | </div> | 42 | </div> |
43 | |||
44 | <!-- end left sidebar container --> | 43 | <!-- end left sidebar container --> |
44 | |||
45 | <!-- Begin right container --> | 45 | <!-- Begin right container --> |
46 | <div class="row span10"> | ||
47 | {% block buildinfomain %}{% endblock %} | 46 | {% block buildinfomain %}{% endblock %} |
48 | </div> | 47 | <!-- End right container --> |
49 | 48 | ||
50 | 49 | ||
51 | </div> | 50 | </div> |
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html index 2a6f084929..00703fe4c1 100644 --- a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html +++ b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html | |||
@@ -53,8 +53,8 @@ | |||
53 | $('.progress, .lead span').tooltip({container:'table', placement:'top'}); | 53 | $('.progress, .lead span').tooltip({container:'table', placement:'top'}); |
54 | 54 | ||
55 | $(".pagesize").change(function () { | 55 | $(".pagesize").change(function () { |
56 | $(".pagesize option:selected").each(function () | 56 | console.log("page size change"); |
57 | {reload_params({"count":$(this).text()}); }); | 57 | reload_params({"count":$(this).val()}); ; |
58 | }); | 58 | }); |
59 | }); | 59 | }); |
60 | </script> | 60 | </script> |
diff --git a/bitbake/lib/toaster/toastergui/templates/build.html b/bitbake/lib/toaster/toastergui/templates/build.html index 27ce1ccbc5..43b491d558 100644 --- a/bitbake/lib/toaster/toastergui/templates/build.html +++ b/bitbake/lib/toaster/toastergui/templates/build.html | |||
@@ -12,7 +12,6 @@ | |||
12 | Recent Builds | 12 | Recent Builds |
13 | </h1> | 13 | </h1> |
14 | </div> | 14 | </div> |
15 | {{build_mru}} | ||
16 | {% for build in mru %} | 15 | {% for build in mru %} |
17 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> | 16 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> |
18 | <div class="row-fluid"> | 17 | <div class="row-fluid"> |
@@ -74,17 +73,17 @@ | |||
74 | </tr> | 73 | </tr> |
75 | {% for build in objects %} | 74 | {% for build in objects %} |
76 | <tr class="data"> | 75 | <tr class="data"> |
77 | <td class="outcome"><a href="{% url "configuration" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td> | 76 | <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td> |
78 | <td class="target">{% for t in build.target_set.all %}{%if t.is_image %}<a href="{% url "target" build.id t.id %}">{% endif %}{{t.target}}{% if t.is_image %}</a>{% endif %}<br/>{% endfor %}</td> | 77 | <td class="target">{% for t in build.target_set.all %}{%if t.is_image %}<a href="{% url "target" build.id t.id %}">{% endif %}{{t.target}}{% if t.is_image %}</a>{% endif %}<br/>{% endfor %}</td> |
79 | <td class="machine">{{build.machine}}</td> | 78 | <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> |
80 | <td class="started_on">{{build.started_on}}</td> | 79 | <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on}}</a></td> |
81 | <td class="completed_on">{{build.completed_on}}</td> | 80 | <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on}}</a></td> |
82 | <td class="failed_tasks"></td> | 81 | <td class="failed_tasks"></td> |
83 | <td class="errors">{% if build.errors_no %}<a class="error" href="#">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>{%endif%}</td> | 82 | <td class="errors">{% if build.errors_no %}<a class="error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>{%endif%}</td> |
84 | <td class="warnings">{% if build.warnings_no %}<a class="warning" href="#">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td> | 83 | <td class="warnings">{% if build.warnings_no %}<a class="warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td> |
85 | <td class="time">{{build|timespent}}</td> | 84 | <td class="time"><a href="{% url "buildtime" build.id %}">{{build|timespent}}</a></td> |
86 | <td class="log">{{build.log}}</td> | 85 | <td class="log">{{build.log}}</td> |
87 | <td class="output">{% if build.outcome == 0 %}{% for t in build.target_set.all %}{% if t.is_image %}{{build.image_fstypes}}{% endif %}{% endfor %}{% endif %}</td> | 86 | <td class="output">{% if build.outcome == 0 %}{% for t in build.target_set.all %}{% if t.is_image %}<a href="{%url "builddashboard" build.id%}#images">{{build.image_fstypes}}</a>{% endif %}{% endfor %}{% endif %}</td> |
88 | </tr> | 87 | </tr> |
89 | 88 | ||
90 | {% endfor %} | 89 | {% endfor %} |
diff --git a/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/bitbake/lib/toaster/toastergui/templates/builddashboard.html index 7c58cc0b25..3b184372bf 100644 --- a/bitbake/lib/toaster/toastergui/templates/builddashboard.html +++ b/bitbake/lib/toaster/toastergui/templates/builddashboard.html | |||
@@ -1,8 +1,74 @@ | |||
1 | {% extends "basebuildpage.html" %} | 1 | {% extends "basebuildpage.html" %} |
2 | {% load humanize %} | ||
3 | {% load projecttags %} | ||
2 | {% block localbreadcrumb %} | 4 | {% block localbreadcrumb %} |
3 | <li>Dashboard</li> | 5 | <li>Dashboard</li> |
4 | {% endblock %} | 6 | {% endblock %} |
5 | 7 | ||
6 | {% block buildinfomain %} | 8 | {% block buildinfomain %} |
9 | <!-- page title --> | ||
10 | <div class="row-fluid span10"> | ||
11 | <div class="page-header"> | ||
12 | <h1>{{build.target_set.all|join:" "}} {{build.machine}}</h1> | ||
13 | </div> | ||
14 | </div> | ||
15 | |||
16 | <!-- build result bar --> | ||
17 | <div class="row-fluid span10 pull-right"> | ||
18 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> | ||
19 | <div class="row-fluid lead"> | ||
20 | <span class="pull-left"><strong>{%if build.outcome == build.SUCCEEDED%}Completed{%elif build.outcome == build.FAILED%}Failed{%else%}{%endif%}</strong> {{build.completed_on|naturaltime}} with </span>{%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}{% if build.errors_no %} | ||
21 | <span class="span2"><i class="icon-minus-sign red"></i><strong><a href="{%url 'builddashboard' build.pk%}" class="error"> {{build.errors_no}} error{{build.errors_no|pluralize}}</a></strong></span> | ||
22 | {% endif %} | ||
23 | {% if build.warnings_no %} | ||
24 | <span class="span2"><i class="icon-warning-sign yellow"></i><strong><a href="{%url 'builddashboard' build.pk%}" class="warning"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span> | ||
25 | {% endif %} | ||
26 | <span class="pull-right">Build time: <a href="build-time.html">{{ build|timespent }}</a></span> | ||
27 | {%endif%} | ||
28 | </div> | ||
29 | </div> | ||
30 | </div> | ||
31 | |||
32 | {%if build.outcome == build.SUCCEEDED%} | ||
33 | <!-- built images --> | ||
34 | <div class="row-fluid span10 pull-right"> | ||
35 | <h2>Images</h2> | ||
36 | |||
37 | <div class="well" style="background-color:transparent;"> | ||
38 | </div> | ||
39 | </div> | ||
40 | |||
41 | {%else%} | ||
42 | <!-- error dump --> | ||
43 | {%endif%} | ||
44 | |||
45 | <!-- build summary --> | ||
46 | <div class="row-fluid span10 pull-right"> | ||
47 | <h2>Build summary</h2> | ||
48 | <div class="well span4" style="margin-left:0px; background-color:transparent;"> | ||
49 | <h4><a href="{%url 'configuration' build.pk%}">Configuration</a></h4> | ||
50 | <dl> | ||
51 | <dt>Machine</dt><dd>{{build.machine}}</dd> | ||
52 | <dt>Distro</dt><dd></dd> | ||
53 | <dt>Layers</dt>{% for i in build.layer_version_build.all %}<dd>{{i.layer.name}}</dd>{%endfor%} | ||
54 | </dl> | ||
55 | </div> | ||
56 | <div class="well span4" style="background-color:transparent;"> | ||
57 | <h4><a href="{%url 'tasks' build.pk%}">Tasks</a></h4> | ||
58 | <dl> | ||
59 | <dt>Total number of tasks</dt><dd>{{build.task_build.all.count}}</dd> | ||
60 | <dt>Tasks executed</dt><dd>{% query build.task_build task_executed=1 order__gt=0 as exectask%}{{exectask.count}}</dd> | ||
61 | <dt>Tasks prebuilt</dt><dd>{% query build.task_build task_executed=0 order__gt=0 as noexectask%}{{noexectask.count}}</dd> | ||
62 | <dt>Reuse</dt><dd>{% query build.task_build order__gt=0 as texec %}{{noexectask.count|multiply:100|divide:texec.count}}%</dd> | ||
63 | </dl> | ||
64 | </div> | ||
65 | <div class="well span4" style="background-color:transparent;"> | ||
66 | <h4><a href="{% url 'recipes' build.pk %}">Recipes</a> & <a href="{% url 'packages' build.pk %}">Packages</a></h4> | ||
67 | <dl> | ||
68 | <dt>Recipes used</dt><dd>{{recipecount}}</dd> | ||
69 | <dt>Packages built</dt><dd>{{build.package_set.all.count}}</dd> | ||
70 | </dl> | ||
71 | </div> | ||
72 | </div> | ||
7 | 73 | ||
8 | {% endblock %} | 74 | {% endblock %} |
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py index 5f60379932..1455026754 100644 --- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py +++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py | |||
@@ -29,3 +29,21 @@ def time_difference(start_time, end_time): | |||
29 | def timespent(build_object): | 29 | def timespent(build_object): |
30 | tdsec = (build_object.completed_on - build_object.started_on).total_seconds() | 30 | tdsec = (build_object.completed_on - build_object.started_on).total_seconds() |
31 | return "%02d:%02d:%02d" % (int(tdsec/3600), int((tdsec - tdsec/ 3600)/ 60), int(tdsec) % 60) | 31 | return "%02d:%02d:%02d" % (int(tdsec/3600), int((tdsec - tdsec/ 3600)/ 60), int(tdsec) % 60) |
32 | |||
33 | @register.assignment_tag | ||
34 | def query(qs, **kwargs): | ||
35 | """ template tag which allows queryset filtering. Usage: | ||
36 | {% query books author=author as mybooks %} | ||
37 | {% for book in mybooks %} | ||
38 | ... | ||
39 | {% endfor %} | ||
40 | """ | ||
41 | return qs.filter(**kwargs) | ||
42 | |||
43 | @register.filter | ||
44 | def divide(value, arg): | ||
45 | return int(value) / int(arg) | ||
46 | |||
47 | @register.filter | ||
48 | def multiply(value, arg): | ||
49 | return int(value) * int(arg) | ||
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 663e03dfd2..7d4d710f83 100644 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
@@ -59,10 +59,10 @@ def _verify_parameters(g, mandatory_parameters): | |||
59 | return miss | 59 | return miss |
60 | return None | 60 | return None |
61 | 61 | ||
62 | def _redirect_parameters(view, g, mandatory_parameters): | 62 | def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs): |
63 | import urllib | 63 | import urllib |
64 | from django.core.urlresolvers import reverse | 64 | from django.core.urlresolvers import reverse |
65 | url = reverse(view) | 65 | url = reverse(view, kwargs=kwargs) |
66 | params = {} | 66 | params = {} |
67 | for i in g: | 67 | for i in g: |
68 | params[i] = g[i] | 68 | params[i] = g[i] |
@@ -70,7 +70,7 @@ def _redirect_parameters(view, g, mandatory_parameters): | |||
70 | if not i in params: | 70 | if not i in params: |
71 | params[i] = mandatory_parameters[i] | 71 | params[i] = mandatory_parameters[i] |
72 | 72 | ||
73 | return redirect(url + "?%s" % urllib.urlencode(params)) | 73 | return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs) |
74 | 74 | ||
75 | 75 | ||
76 | # shows the "all builds" page | 76 | # shows the "all builds" page |
@@ -82,7 +82,7 @@ def builds(request): | |||
82 | mandatory_parameters = { 'count': 10, 'page' : 1}; | 82 | mandatory_parameters = { 'count': 10, 'page' : 1}; |
83 | retval = _verify_parameters( request.GET, mandatory_parameters ) | 83 | retval = _verify_parameters( request.GET, mandatory_parameters ) |
84 | if retval: | 84 | if retval: |
85 | return _redirect_parameters( builds, request.GET, mandatory_parameters) | 85 | return _redirect_parameters( 'all-builds', request.GET, mandatory_parameters) |
86 | 86 | ||
87 | # retrieve the objects that will be displayed in the table | 87 | # retrieve the objects that will be displayed in the table |
88 | build_info = _build_page_range(Paginator(Build.objects.exclude(outcome = Build.IN_PROGRESS).order_by("-id"), request.GET.get('count', 10)),request.GET.get('page', 1)) | 88 | build_info = _build_page_range(Paginator(Build.objects.exclude(outcome = Build.IN_PROGRESS).order_by("-id"), request.GET.get('count', 10)),request.GET.get('page', 1)) |
@@ -125,6 +125,7 @@ def builddashboard(request, build_id): | |||
125 | return redirect(builds) | 125 | return redirect(builds) |
126 | context = { | 126 | context = { |
127 | 'build' : Build.objects.filter(pk=build_id)[0], | 127 | 'build' : Build.objects.filter(pk=build_id)[0], |
128 | 'recipecount' : Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)).count() | ||
128 | } | 129 | } |
129 | return render(request, template, context) | 130 | return render(request, template, context) |
130 | 131 | ||
@@ -186,8 +187,12 @@ def _find_task_provider(task): | |||
186 | 187 | ||
187 | def tasks(request, build_id): | 188 | def tasks(request, build_id): |
188 | template = 'task.html' | 189 | template = 'task.html' |
190 | mandatory_parameters = { 'count': 100, 'page' : 1}; | ||
191 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
192 | if retval: | ||
193 | return _redirect_parameters( 'tasks', request.GET, mandatory_parameters, build_id = build_id) | ||
189 | 194 | ||
190 | tasks = _build_page_range(Paginator(Task.objects.filter(build=build_id), 100),request.GET.get('page', 1)) | 195 | tasks = _build_page_range(Paginator(Task.objects.filter(build=build_id, order__gt=0), request.GET.get('count', 100)),request.GET.get('page', 1)) |
191 | 196 | ||
192 | for t in tasks: | 197 | for t in tasks: |
193 | if t.outcome == Task.OUTCOME_COVERED: | 198 | if t.outcome == Task.OUTCOME_COVERED: |
@@ -199,16 +204,25 @@ def tasks(request, build_id): | |||
199 | 204 | ||
200 | def recipes(request, build_id): | 205 | def recipes(request, build_id): |
201 | template = 'recipe.html' | 206 | template = 'recipe.html' |
207 | mandatory_parameters = { 'count': 100, 'page' : 1}; | ||
208 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
209 | if retval: | ||
210 | return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id) | ||
202 | 211 | ||
203 | recipes = _build_page_range(Paginator(Recipe.objects.filter(build_recipe=build_id), 100),request.GET.get('page', 1)) | 212 | recipes = _build_page_range(Paginator(Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)), request.GET.get('count', 100)),request.GET.get('page', 1)) |
204 | 213 | ||
205 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects': recipes} | 214 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects': recipes, } |
206 | 215 | ||
207 | return render(request, template, context) | 216 | return render(request, template, context) |
208 | 217 | ||
209 | 218 | ||
210 | def configuration(request, build_id): | 219 | def configuration(request, build_id): |
211 | template = 'configuration.html' | 220 | template = 'configuration.html' |
221 | mandatory_parameters = { 'count': 100, 'page' : 1}; | ||
222 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
223 | if retval: | ||
224 | return _redirect_parameters( 'configuration', request.GET, mandatory_parameters, build_id = build_id) | ||
225 | |||
212 | variables = _build_page_range(Paginator(Variable.objects.filter(build=build_id), 50), request.GET.get('page', 1)) | 226 | variables = _build_page_range(Paginator(Variable.objects.filter(build=build_id), 50), request.GET.get('page', 1)) |
213 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : variables} | 227 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : variables} |
214 | return render(request, template, context) | 228 | return render(request, template, context) |
@@ -245,7 +259,13 @@ def diskio(request, build_id): | |||
245 | 259 | ||
246 | def bpackage(request, build_id): | 260 | def bpackage(request, build_id): |
247 | template = 'bpackage.html' | 261 | template = 'bpackage.html' |
248 | packages = Package.objects.filter(build = build_id) | 262 | mandatory_parameters = { 'count': 100, 'page' : 1}; |
263 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
264 | if retval: | ||
265 | return _redirect_parameters( 'packages', request.GET, mandatory_parameters, build_id = build_id) | ||
266 | |||
267 | packages = _build_page_range(Paginator(Package.objects.filter(build = build_id), request.GET.get('count', 100)),request.GET.get('page', 1)) | ||
268 | |||
249 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages} | 269 | context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages} |
250 | return render(request, template, context) | 270 | return render(request, template, context) |
251 | 271 | ||