]> git.ipfire.org Git - thirdparty/openembedded/openembedded-core-contrib.git/commitdiff
toaster: Build dashboard implementation
authorAlexandru DAMIAN <alexandru.damian@intel.com>
Fri, 13 Dec 2013 17:14:34 +0000 (17:14 +0000)
committerPaul Eggleton <paul.eggleton@linux.intel.com>
Fri, 10 Jan 2014 14:13:50 +0000 (14:13 +0000)
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]

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
lib/toaster/toastergui/templates/basebuildpage.html
lib/toaster/toastergui/templates/basetable_bottom.html
lib/toaster/toastergui/templates/build.html
lib/toaster/toastergui/templates/builddashboard.html
lib/toaster/toastergui/templatetags/projecttags.py
lib/toaster/toastergui/views.py

index 1b037f9539fc95469abdf03210c1cb688300934f..7d2a1f388ef31a9f2cb20fe2f5a93fb1c13ca09f 100644 (file)
@@ -3,7 +3,7 @@
 {% block pagecontent %}
 
 
- <div class="span12">
+ <div class="">
 <!-- Breadcrumbs -->
     <div class="section">
         <ul class="breadcrumb" id="breadcrumb">
                 <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
             </ul>
         </div>
-
         <!-- end left sidebar container -->
+
         <!-- Begin right container -->
-        <div class="row span10">
         {% block buildinfomain %}{% endblock %}
-        </div>
+        <!-- End right container -->
 
 
     </div>
index 2a6f0849299ca220a30a8bf56eaa2eb4d6e8a635..00703fe4c1c4cea263ac83a441159cb09e5b44df 100644 (file)
@@ -53,8 +53,8 @@
     $('.progress, .lead span').tooltip({container:'table', placement:'top'});
 
     $(".pagesize").change(function () {
-        $(".pagesize option:selected").each(function ()
-            {reload_params({"count":$(this).text()}); });
+        console.log("page size change");
+        reload_params({"count":$(this).val()}); ;
     });
 });
 </script>
index 27ce1ccbc543761ab5d4339332f230474c1cd655..43b491d55815e472ea5b218fd7a3c2d51d031f0a 100644 (file)
@@ -12,7 +12,6 @@
         Recent Builds
      </h1>
 </div>
-{{build_mru}}
 {% for build in mru %}
 <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}">
     <div class="row-fluid">
         </tr>
         {% for build in objects %}
         <tr class="data">
-            <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>
+            <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>
             <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>
-            <td class="machine">{{build.machine}}</td>
-            <td class="started_on">{{build.started_on}}</td>
-            <td class="completed_on">{{build.completed_on}}</td>
+            <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
+            <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on}}</a></td>
+            <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on}}</a></td>
             <td class="failed_tasks"></td>
-            <td class="errors">{% if  build.errors_no %}<a class="error" href="#">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>{%endif%}</td>
-            <td class="warnings">{% if  build.warnings_no %}<a class="warning" href="#">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td>
-            <td class="time">{{build|timespent}}</td>
+            <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>
+            <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>
+            <td class="time"><a href="{% url "buildtime" build.id %}">{{build|timespent}}</a></td>
             <td class="log">{{build.log}}</td>
-            <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>
+            <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>
         </tr>
 
         {% endfor %}
index 7c58cc0b25d10782e9482fecfc79c3a45698c275..3b184372bfa65b7ad9a32d743a66c3ec6bbee879 100644 (file)
@@ -1,8 +1,74 @@
 {% extends "basebuildpage.html" %}
+{% load humanize %}
+{% load projecttags %}
 {% block localbreadcrumb %}
 <li>Dashboard</li>
 {% endblock %}
 
 {% block buildinfomain %}
+<!-- page title -->
+<div class="row-fluid span10">
+ <div class="page-header">
+     <h1>{{build.target_set.all|join:" "}} {{build.machine}}</h1>
+ </div>
+</div>
+
+<!-- build result bar -->
+<div class="row-fluid span10 pull-right">
+  <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}">
+    <div class="row-fluid lead">
+            <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 %}
+            <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>
+{% endif %}
+{% if  build.warnings_no %}
+            <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>
+{% endif %}
+            <span class="pull-right">Build time: <a href="build-time.html">{{ build|timespent }}</a></span>
+{%endif%}
+    </div>
+  </div>
+</div>
+
+{%if build.outcome == build.SUCCEEDED%}
+<!-- built images -->
+<div class="row-fluid span10 pull-right">
+  <h2>Images</h2>
+
+<div class="well" style="background-color:transparent;">
+</div>
+</div>
+
+{%else%}
+<!-- error dump -->
+{%endif%}
+
+<!-- build summary -->
+<div class="row-fluid span10 pull-right">
+<h2>Build summary</h2>
+    <div class="well span4" style="margin-left:0px; background-color:transparent;">
+        <h4><a href="{%url 'configuration' build.pk%}">Configuration</a></h4>
+            <dl>
+        <dt>Machine</dt><dd>{{build.machine}}</dd>
+        <dt>Distro</dt><dd></dd>
+        <dt>Layers</dt>{% for i in build.layer_version_build.all %}<dd>{{i.layer.name}}</dd>{%endfor%}
+            </dl>
+    </div>
+    <div class="well span4" style="background-color:transparent;">
+        <h4><a href="{%url 'tasks' build.pk%}">Tasks</a></h4>
+            <dl>
+        <dt>Total number of tasks</dt><dd>{{build.task_build.all.count}}</dd>
+        <dt>Tasks executed</dt><dd>{% query build.task_build task_executed=1 order__gt=0 as exectask%}{{exectask.count}}</dd>
+        <dt>Tasks prebuilt</dt><dd>{% query build.task_build task_executed=0 order__gt=0 as noexectask%}{{noexectask.count}}</dd>
+        <dt>Reuse</dt><dd>{% query build.task_build order__gt=0 as texec %}{{noexectask.count|multiply:100|divide:texec.count}}%</dd>
+            </dl>
+    </div>
+    <div class="well span4" style="background-color:transparent;">
+        <h4><a href="{% url 'recipes' build.pk %}">Recipes</a> & <a href="{% url 'packages' build.pk %}">Packages</a></h4>
+            <dl>
+        <dt>Recipes used</dt><dd>{{recipecount}}</dd>
+        <dt>Packages built</dt><dd>{{build.package_set.all.count}}</dd>
+            </dl>
+    </div>
+</div>
 
 {% endblock %}
index 5f60379932201b258c54a3c0c033be2e1c64b649..14550267545abf764a0ce9ec36a33e522caa0094 100644 (file)
@@ -29,3 +29,21 @@ def time_difference(start_time, end_time):
 def timespent(build_object):
     tdsec = (build_object.completed_on - build_object.started_on).total_seconds()
     return "%02d:%02d:%02d" % (int(tdsec/3600), int((tdsec - tdsec/ 3600)/ 60), int(tdsec) % 60)
+
+@register.assignment_tag
+def query(qs, **kwargs):
+    """ template tag which allows queryset filtering. Usage:
+          {% query books author=author as mybooks %}
+          {% for book in mybooks %}
+            ...
+          {% endfor %}
+    """
+    return qs.filter(**kwargs)
+
+@register.filter
+def divide(value, arg):
+    return int(value) / int(arg)
+
+@register.filter
+def multiply(value, arg):
+    return int(value) * int(arg)
index 663e03dfd26b2a9128882ae11c914c74fb388a23..7d4d710f83379f842371ddea7edae336ab419926 100644 (file)
@@ -59,10 +59,10 @@ def _verify_parameters(g, mandatory_parameters):
         return miss
     return None
 
-def _redirect_parameters(view, g, mandatory_parameters):
+def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs):
     import urllib
     from django.core.urlresolvers import reverse
-    url = reverse(view)
+    url = reverse(view, kwargs=kwargs)
     params = {}
     for i in g:
         params[i] = g[i]
@@ -70,7 +70,7 @@ def _redirect_parameters(view, g, mandatory_parameters):
         if not i in params:
             params[i] = mandatory_parameters[i]
 
-    return redirect(url + "?%s" % urllib.urlencode(params))
+    return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs)
 
 
 # shows the "all builds" page
@@ -82,7 +82,7 @@ def builds(request):
     mandatory_parameters = { 'count': 10,  'page' : 1};
     retval = _verify_parameters( request.GET, mandatory_parameters )
     if retval:
-        return _redirect_parameters( builds, request.GET, mandatory_parameters)
+        return _redirect_parameters( 'all-builds', request.GET, mandatory_parameters)
 
     # retrieve the objects that will be displayed in the table
     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):
         return redirect(builds)
     context = {
             'build' : Build.objects.filter(pk=build_id)[0],
+            'recipecount' : Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)).count()
     }
     return render(request, template, context)
 
@@ -186,8 +187,12 @@ def _find_task_provider(task):
 
 def tasks(request, build_id):
     template = 'task.html'
+    mandatory_parameters = { 'count': 100,  'page' : 1};
+    retval = _verify_parameters( request.GET, mandatory_parameters )
+    if retval:
+        return _redirect_parameters( 'tasks', request.GET, mandatory_parameters, build_id = build_id)
 
-    tasks = _build_page_range(Paginator(Task.objects.filter(build=build_id), 100),request.GET.get('page', 1))
+    tasks = _build_page_range(Paginator(Task.objects.filter(build=build_id, order__gt=0), request.GET.get('count', 100)),request.GET.get('page', 1))
 
     for t in tasks:
         if t.outcome == Task.OUTCOME_COVERED:
@@ -199,16 +204,25 @@ def tasks(request, build_id):
 
 def recipes(request, build_id):
     template = 'recipe.html'
+    mandatory_parameters = { 'count': 100,  'page' : 1};
+    retval = _verify_parameters( request.GET, mandatory_parameters )
+    if retval:
+        return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id)
 
-    recipes = _build_page_range(Paginator(Recipe.objects.filter(build_recipe=build_id), 100),request.GET.get('page', 1))
+    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))
 
-    context = {'build': Build.objects.filter(pk=build_id)[0], 'objects': recipes}
+    context = {'build': Build.objects.filter(pk=build_id)[0], 'objects': recipes}
 
     return render(request, template, context)
 
 
 def configuration(request, build_id):
     template = 'configuration.html'
+    mandatory_parameters = { 'count': 100,  'page' : 1};
+    retval = _verify_parameters( request.GET, mandatory_parameters )
+    if retval:
+        return _redirect_parameters( 'configuration', request.GET, mandatory_parameters, build_id = build_id)
+
     variables = _build_page_range(Paginator(Variable.objects.filter(build=build_id), 50), request.GET.get('page', 1))
     context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : variables}
     return render(request, template, context)
@@ -245,7 +259,13 @@ def diskio(request, build_id):
 
 def bpackage(request, build_id):
     template = 'bpackage.html'
-    packages = Package.objects.filter(build = build_id)
+    mandatory_parameters = { 'count': 100,  'page' : 1};
+    retval = _verify_parameters( request.GET, mandatory_parameters )
+    if retval:
+        return _redirect_parameters( 'packages', request.GET, mandatory_parameters, build_id = build_id)
+
+    packages = _build_page_range(Paginator(Package.objects.filter(build = build_id), request.GET.get('count', 100)),request.GET.get('page', 1))
+
     context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages}
     return render(request, template, context)