diff options
Diffstat (limited to 'bitbake/lib')
10 files changed, 384 insertions, 78 deletions
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_top.html b/bitbake/lib/toaster/toastergui/templates/basetable_top.html index e3f6a4ee23..92a3b50801 100644 --- a/bitbake/lib/toaster/toastergui/templates/basetable_top.html +++ b/bitbake/lib/toaster/toastergui/templates/basetable_top.html | |||
| @@ -175,8 +175,8 @@ | |||
| 175 | <button class="btn" type="submit" value="Search">Search</button> | 175 | <button class="btn" type="submit" value="Search">Search</button> |
| 176 | </form> | 176 | </form> |
| 177 | <div class="pull-right"> | 177 | <div class="pull-right"> |
| 178 | {% block custombuttons%} {% endblock %} | ||
| 178 | {% if tablecols %} | 179 | {% if tablecols %} |
| 179 | {% block custombuttons%} {% endblock %} | ||
| 180 | <div class="btn-group"> | 180 | <div class="btn-group"> |
| 181 | <button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns | 181 | <button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns |
| 182 | <span class="caret"></span> | 182 | <span class="caret"></span> |
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_top_buildprojects.html b/bitbake/lib/toaster/toastergui/templates/basetable_top_buildprojects.html new file mode 100644 index 0000000000..d517179592 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/basetable_top_buildprojects.html | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | {% extends "basetable_top.html" %} | ||
| 2 | |||
| 3 | {%block custombuttons %} | ||
| 4 | {% if MANAGED %} | ||
| 5 | <div class="btn-group builds-projects"> | ||
| 6 | <button class="btn dropdown-toggle" data-toggle="dropdown"> | ||
| 7 | <span class="selection">Show all builds</span> | ||
| 8 | <i class="icon-caret-down"></i> | ||
| 9 | </button> | ||
| 10 | <ul class="dropdown-menu"> | ||
| 11 | <li><a href="{% url 'all-builds'%}">Show all builds</a></li> | ||
| 12 | <li><a href="{% url 'all-projects'%}">Show all projects</a></li> | ||
| 13 | </ul> | ||
| 14 | </div> | ||
| 15 | {% endif %} | ||
| 16 | {%endblock%} | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_top_projectbuilds.html b/bitbake/lib/toaster/toastergui/templates/basetable_top_projectbuilds.html new file mode 100644 index 0000000000..bfefff5e33 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/basetable_top_projectbuilds.html | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | {% extends "basetable_top.html" %} | ||
| 2 | |||
| 3 | {%block custombuttons %} | ||
| 4 | {% if MANAGED %} | ||
| 5 | <div class="btn-group builds-projects"> | ||
| 6 | <button class="btn dropdown-toggle" data-toggle="dropdown"> | ||
| 7 | <span class="selection">Show all projects</span> | ||
| 8 | <i class="icon-caret-down"></i> | ||
| 9 | </button> | ||
| 10 | <ul class="dropdown-menu"> | ||
| 11 | <li><a href="{% url 'all-builds'%}">Show all builds</a></li> | ||
| 12 | <li><a href="{% url 'all-projects'%}">Show all projects</a></li> | ||
| 13 | </ul> | ||
| 14 | </div> | ||
| 15 | {% endif %} | ||
| 16 | {%endblock%} | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/build.html b/bitbake/lib/toaster/toastergui/templates/build.html index bef1f15399..f20f041749 100644 --- a/bitbake/lib/toaster/toastergui/templates/build.html +++ b/bitbake/lib/toaster/toastergui/templates/build.html | |||
| @@ -6,83 +6,11 @@ | |||
| 6 | 6 | ||
| 7 | {% block pagecontent %} | 7 | {% block pagecontent %} |
| 8 | <div class="row-fluid"> | 8 | <div class="row-fluid"> |
| 9 | {% if not objects.paginator.count and not request.GET.filter and not request.GET.search %} | ||
| 10 | <!-- Empty - no data in database --> | ||
| 11 | <div class="hero-unit span12"> | ||
| 12 | <button type="button" class="close" data-dismiss="alert">×</button> | ||
| 13 | <div class="row-fluid"> | ||
| 14 | <div class="span6"> | ||
| 15 | <h1>This is Toaster</h1> | ||
| 16 | <p>A web interface to <a href="http://www.yoctoproject.org/tools-resources/projects/bitbake">BitBake</a>, the <a href="http://www.yoctoproject.org">Yocto Project</a> build system.</p> | ||
| 17 | <p class="hero-actions"> | ||
| 18 | <a class="btn btn-primary btn-large" href="https://www.yoctoproject.org/documentation/toaster-manual">Show me the manual</a> | ||
| 19 | <a class="btn btn-large" href="https://wiki.yoctoproject.org/wiki/Contribute_to_Toaster">I want to contribute</a> | ||
| 20 | </p> | ||
| 21 | </div> | ||
| 22 | <div class="span5"> | ||
| 23 | <a href="http://www.yoctoproject.org"><img src="{% static 'img/toaster.png' %}" class="thumbnail" alt="Yocto Project"/> </a> | ||
| 24 | </div> | ||
| 25 | </div> | ||
| 26 | </div> | ||
| 27 | {% endif %} | ||
| 28 | 9 | ||
| 29 | {%if mru.count > 0%} | 10 | {% include "mrb_section.html" %} |
| 30 | <div class="page-header top-air"> | ||
| 31 | <h1> | ||
| 32 | Recent Builds | ||
| 33 | </h1> | ||
| 34 | </div> | ||
| 35 | {% for build in mru %} | ||
| 36 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> | ||
| 37 | <div class="row-fluid"> | ||
| 38 | <div class="lead span5"> | ||
| 39 | {%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%} | ||
| 40 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
| 41 | <a href="{%url 'builddashboard' build.pk%}" class="{%if build.outcome == build.SUCCEEDED %}success{%else%}error{%endif%}"> | ||
| 42 | {% endif %} | ||
| 43 | <span data-toggle="tooltip" {%if build.target_set.all.count > 1%}title="Targets: {%for target in build.target_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|naturaltime}})</span> | ||
| 44 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
| 45 | </a> | ||
| 46 | {% endif %} | ||
| 47 | </div> | ||
| 48 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
| 49 | <div class="span2 lead"> | ||
| 50 | {% if build.errors_no %} | ||
| 51 | <i class="icon-minus-sign red"></i> <a href="{%url 'builddashboard' build.pk%}#errors" class="error">{{build.errors_no}} error{{build.errors_no|pluralize}}</a> | ||
| 52 | {% endif %} | ||
| 53 | </div> | ||
| 54 | <div class="span2 lead"> | ||
| 55 | {% if build.warnings_no %} | ||
| 56 | <i class="icon-warning-sign yellow"></i> <a href="{%url 'builddashboard' build.pk%}#warnings" class="warning">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a> | ||
| 57 | {% endif %} | ||
| 58 | </div> | ||
| 59 | <div class="lead pull-right"> | ||
| 60 | Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a> | ||
| 61 | </div> | ||
| 62 | {%endif%}{%if build.outcome == build.IN_PROGRESS %} | ||
| 63 | <div class="span4"> | ||
| 64 | <div class="progress" style="margin-top:5px;" data-toggle="tooltip" title="{{build.completeper}}% of tasks complete"> | ||
| 65 | <div style="width: {{build.completeper}}%;" class="bar"></div> | ||
| 66 | </div> | ||
| 67 | </div> | ||
| 68 | <div class="lead pull-right">ETA: in {{build.eta|naturaltime}}</div> | ||
| 69 | {%endif%} | ||
| 70 | </div> | ||
| 71 | </div> | ||
| 72 | 11 | ||
| 73 | {% endfor %}{%endif%} | ||
| 74 | 12 | ||
| 75 | {% if not objects.paginator.count and not request.GET.filter and not request.GET.search %} | 13 | {% if 1 %} |
| 76 | <!-- Empty - no data in database --> | ||
| 77 | {% if mru.count == 0 %} | ||
| 78 | <div class="page-header top-air"> | ||
| 79 | <h1>All builds</h1> | ||
| 80 | </div> | ||
| 81 | <div class="alert alert-info lead"> | ||
| 82 | Toaster has not recorded any builds yet. Go build something with <a href="http://www.yoctoproject.org/docs/current/yocto-project-qs/yocto-project-qs.html#test-run">Knotty</a> or <a href="https://www.yoctoproject.org/documentation/hob-manual">Hob</a> | ||
| 83 | </div> | ||
| 84 | {% endif %} | ||
| 85 | {% else %} | ||
| 86 | <div class="page-header top-air"> | 14 | <div class="page-header top-air"> |
| 87 | <h1> | 15 | <h1> |
| 88 | {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} | 16 | {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} |
| @@ -108,7 +36,7 @@ | |||
| 108 | 36 | ||
| 109 | 37 | ||
| 110 | {% else %} | 38 | {% else %} |
| 111 | {% include "basetable_top.html" %} | 39 | {% include "basetable_top_buildprojects.html" %} |
| 112 | <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work --> | 40 | <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work --> |
| 113 | {% for build in objects %} | 41 | {% for build in objects %} |
| 114 | <tr class="data"> | 42 | <tr class="data"> |
diff --git a/bitbake/lib/toaster/toastergui/templates/landing.html b/bitbake/lib/toaster/toastergui/templates/landing.html new file mode 100644 index 0000000000..071edf86ef --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/landing.html | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | {% extends "base.html" %} | ||
| 2 | |||
| 3 | {% load static %} | ||
| 4 | {% load projecttags %} | ||
| 5 | {% load humanize %} | ||
| 6 | |||
| 7 | {% block pagecontent %} | ||
| 8 | |||
| 9 | <div class="container-fluid"> | ||
| 10 | <div class="row-fluid"> | ||
| 11 | <!-- Empty - no data in database --> | ||
| 12 | <div class="hero-unit span12"> | ||
| 13 | <button class="close" data-dismiss="alert" type="button"> | ||
| 14 | × | ||
| 15 | </button> | ||
| 16 | <div class="row-fluid"> | ||
| 17 | <div class="span6"> | ||
| 18 | <h1> | ||
| 19 | This is Toaster | ||
| 20 | </h1> | ||
| 21 | <p> | ||
| 22 | A web interface to | ||
| 23 | <a href="http://www.yoctoproject.org/tools-resources/projects/bitbake"> | ||
| 24 | BitBake | ||
| 25 | </a> | ||
| 26 | , the | ||
| 27 | <a href="http://www.yoctoproject.org"> | ||
| 28 | Yocto Project | ||
| 29 | </a> | ||
| 30 | build system. | ||
| 31 | </p> | ||
| 32 | <p class="hero-actions"> | ||
| 33 | <a class="btn btn-primary btn-large" href="https://www.yoctoproject.org/documentation/toaster-manual"> | ||
| 34 | Show me the manual | ||
| 35 | </a> | ||
| 36 | <a class="btn btn-large" href="https://wiki.yoctoproject.org/wiki/Contribute_to_Toaster"> | ||
| 37 | I want to contribute | ||
| 38 | </a> | ||
| 39 | </p> | ||
| 40 | </div> | ||
| 41 | <div class="span5"> | ||
| 42 | <a href="http://www.yoctoproject.org"> | ||
| 43 | <img alt="Yocto Project" class="thumbnail" src="/static/img/toaster.png"/> | ||
| 44 | </a> | ||
| 45 | </div> | ||
| 46 | </div> | ||
| 47 | </div> | ||
| 48 | <!-- Empty - no data in database --> | ||
| 49 | <div class="page-header top-air"> | ||
| 50 | <h1> | ||
| 51 | All builds | ||
| 52 | </h1> | ||
| 53 | </div> | ||
| 54 | <div class="alert alert-info lead"> | ||
| 55 | Toaster has not recorded any builds yet. Go build something with | ||
| 56 | <a href="http://www.yoctoproject.org/docs/current/yocto-project-qs/yocto-project-qs.html#test-run"> | ||
| 57 | Knotty | ||
| 58 | </a> | ||
| 59 | or | ||
| 60 | <a href="https://www.yoctoproject.org/documentation/hob-manual"> | ||
| 61 | Hob | ||
| 62 | </a> | ||
| 63 | </div> | ||
| 64 | </div> | ||
| 65 | |||
| 66 | {% endblock %} | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/bitbake/lib/toaster/toastergui/templates/mrb_section.html new file mode 100644 index 0000000000..5ba0b08495 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/mrb_section.html | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | {% load static %} | ||
| 2 | {% load projecttags %} | ||
| 3 | {% load humanize %} | ||
| 4 | |||
| 5 | |||
| 6 | {%if mru.count > 0%} | ||
| 7 | |||
| 8 | <div class="page-header top-air"> | ||
| 9 | <h1> | ||
| 10 | Latest Builds | ||
| 11 | </h1> | ||
| 12 | </div> | ||
| 13 | <div id="latest-builds"> | ||
| 14 | {% for build in mru %} | ||
| 15 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}" style="padding-top: 0;"> | ||
| 16 | {% if build.project %} | ||
| 17 | <span class="label {%if build.outcome == build.SUCCEEDED%}label-success{%elif build.outcome == build.FAILED%}label-danger{%else%}label-info{%endif%}" style="font-weight: normal; margin-bottom: 5px; margin-left:-15px; padding-top:5px;"> {{build.project.name}} </span> | ||
| 18 | {% endif %} | ||
| 19 | |||
| 20 | <div class="row-fluid"> | ||
| 21 | <div class="span4 lead"> | ||
| 22 | {%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%} | ||
| 23 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
| 24 | <a href="{%url 'builddashboard' build.pk%}" class="{%if build.outcome == build.SUCCEEDED %}success{%else%}error{%endif%}"> | ||
| 25 | {% endif %} | ||
| 26 | <span data-toggle="tooltip" {%if build.target_set.all.count > 1%}title="Targets: {%for target in build.target_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|naturaltime}})</span> | ||
| 27 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
| 28 | </a> | ||
| 29 | {% endif %} | ||
| 30 | </div> | ||
| 31 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
| 32 | <div class="span2 lead"> | ||
| 33 | {% if build.errors_no %} | ||
| 34 | <i class="icon-minus-sign red"></i> <a href="{%url 'builddashboard' build.pk%}#errors" class="error">{{build.errors_no}} error{{build.errors_no|pluralize}}</a> | ||
| 35 | {% endif %} | ||
| 36 | </div> | ||
| 37 | <div class="span2 lead"> | ||
| 38 | {% if build.warnings_no %} | ||
| 39 | <i class="icon-warning-sign yellow"></i> <a href="{%url 'builddashboard' build.pk%}#warnings" class="warning">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a> | ||
| 40 | {% endif %} | ||
| 41 | </div> | ||
| 42 | <div class="lead "> | ||
| 43 | <span class="lead{%if not build.project%} pull-right{%endif%}"> | ||
| 44 | Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a> | ||
| 45 | </span> | ||
| 46 | {% if build.project %} | ||
| 47 | <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%elif build.outcome == build.FAILED%}btn-danger{%else%}btn-info{%endif%} pull-right" onclick="scheduleBuild({{build.project.name|json}}, {{build.get_sorted_target_list|mapselect:'target'|json}})">Run again</a> | ||
| 48 | {% endif %} | ||
| 49 | </div> | ||
| 50 | {%endif%} | ||
| 51 | {%if build.outcome == build.IN_PROGRESS %} | ||
| 52 | <div class="span4"> | ||
| 53 | <div class="progress" style="margin-top:5px;" data-toggle="tooltip" title="{{build.completeper}}% of tasks complete"> | ||
| 54 | <div style="width: {{build.completeper}}%;" class="bar"></div> | ||
| 55 | </div> | ||
| 56 | </div> | ||
| 57 | <div class="lead pull-right">ETA: in {{build.eta|naturaltime}}</div> | ||
| 58 | {%endif%} | ||
| 59 | </div> | ||
| 60 | </div> | ||
| 61 | |||
| 62 | {% endfor %} | ||
| 63 | </div> | ||
| 64 | |||
| 65 | <script> | ||
| 66 | |||
| 67 | function _makeXHRBuildCall(data, onsuccess, onfail) { | ||
| 68 | $.ajax( { | ||
| 69 | type: "POST", | ||
| 70 | url: "{% url 'xhr_projectbuild' project.id %}", | ||
| 71 | data: data, | ||
| 72 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, | ||
| 73 | success: function (_data) { | ||
| 74 | if (_data.error != "ok") { | ||
| 75 | alert(_data.error); | ||
| 76 | } else { | ||
| 77 | if (onsuccess != undefined) onsuccess(_data); | ||
| 78 | } | ||
| 79 | }, | ||
| 80 | error: function (_data) { | ||
| 81 | alert("Call failed"); | ||
| 82 | console.log(_data); | ||
| 83 | if (onfail) onfail(data); | ||
| 84 | } | ||
| 85 | }); | ||
| 86 | } | ||
| 87 | |||
| 88 | |||
| 89 | function scheduleBuild(projectName, buildlist) { | ||
| 90 | console.log("scheduleBuild"); | ||
| 91 | // _makeXHRBuildCall({targets: buildlist.join(" ")}, function (_data) { | ||
| 92 | |||
| 93 | $('#latest-builds').prepend('<div class="alert alert-info" style="padding-top:0px">' + '<span class="label label-info" style="font-weight: normal; margin-bottom: 5px; margin-left:-15px; padding-top:5px;">'+projectName+'</span><div class="row-fluid">' + | ||
| 94 | '<div class="span4 lead">' + buildlist.join(" ") + | ||
| 95 | '</div><div class="span4 lead pull-right">Build queued. Your build will start shortly.</div></div></div>'); | ||
| 96 | // } | ||
| 97 | } | ||
| 98 | |||
| 99 | </script> | ||
| 100 | |||
| 101 | {%endif%} | ||
| 102 | |||
diff --git a/bitbake/lib/toaster/toastergui/templates/projects.html b/bitbake/lib/toaster/toastergui/templates/projects.html new file mode 100644 index 0000000000..432f025d3c --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/projects.html | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | {% extends "base.html" %} | ||
| 2 | |||
| 3 | {% load static %} | ||
| 4 | {% load projecttags %} | ||
| 5 | {% load humanize %} | ||
| 6 | |||
| 7 | {% block pagecontent %} | ||
| 8 | |||
| 9 | |||
| 10 | {% include "mrb_section.html" %} | ||
| 11 | |||
| 12 | |||
| 13 | <div class="page-header top-air"> | ||
| 14 | <h1> | ||
| 15 | All projects | ||
| 16 | </h1> | ||
| 17 | </div> | ||
| 18 | |||
| 19 | {% include "basetable_top_projectbuilds.html" %} | ||
| 20 | {% for o in objects %} | ||
| 21 | <tr class="data"> | ||
| 22 | <td><a href="{% url 'project' o.id %}">{{o.name}}</a></td> | ||
| 23 | <td><a href="{% url 'project' o.id %}">{{o.release.name}}</a></td> | ||
| 24 | <td>{{o.get_current_machine_name}}</td> | ||
| 25 | <td>{{o.get_number_of_builds}}</td> | ||
| 26 | <td>{{o.get_last_outcome}}</td> | ||
| 27 | <td>{{o.get_last_target}}</td> | ||
| 28 | <td>{{o.get_last_errors}}</td> | ||
| 29 | <td>{{o.get_last_warnings}}</td> | ||
| 30 | <td>{{o.get_last_imgfiles}}</td> | ||
| 31 | <td>{{o.updated|date:"d/m/y H:i"}}</td> | ||
| 32 | </tr> | ||
| 33 | {% endfor %} | ||
| 34 | {% include "basetable_bottom.html" %} | ||
| 35 | |||
| 36 | {% endblock %} | ||
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py index b953aa1580..4a97eb7ac4 100644 --- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py +++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py | |||
| @@ -24,6 +24,7 @@ import re | |||
| 24 | from django import template | 24 | from django import template |
| 25 | from django.utils import timezone | 25 | from django.utils import timezone |
| 26 | from django.template.defaultfilters import filesizeformat | 26 | from django.template.defaultfilters import filesizeformat |
| 27 | import json as JsonLib | ||
| 27 | 28 | ||
| 28 | register = template.Library() | 29 | register = template.Library() |
| 29 | 30 | ||
| @@ -40,6 +41,16 @@ def sectohms(time): | |||
| 40 | hours = int(tdsec / 3600) | 41 | hours = int(tdsec / 3600) |
| 41 | return "%02d:%02d:%02d" % (hours, int((tdsec - (hours * 3600))/ 60), int(tdsec) % 60) | 42 | return "%02d:%02d:%02d" % (hours, int((tdsec - (hours * 3600))/ 60), int(tdsec) % 60) |
| 42 | 43 | ||
| 44 | |||
| 45 | @register.filter(name = 'mapselect') | ||
| 46 | def mapselect(value, argument): | ||
| 47 | return map(lambda x: vars(x)[argument], value) | ||
| 48 | |||
| 49 | |||
| 50 | @register.filter(name = "json") | ||
| 51 | def json(value): | ||
| 52 | return JsonLib.dumps(value) | ||
| 53 | |||
| 43 | @register.assignment_tag | 54 | @register.assignment_tag |
| 44 | def query(qs, **kwargs): | 55 | def query(qs, **kwargs): |
| 45 | """ template tag which allows queryset filtering. Usage: | 56 | """ template tag which allows queryset filtering. Usage: |
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index e642e32036..07821b6036 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
| @@ -21,6 +21,8 @@ from django.views.generic import RedirectView | |||
| 21 | 21 | ||
| 22 | urlpatterns = patterns('toastergui.views', | 22 | urlpatterns = patterns('toastergui.views', |
| 23 | # landing page | 23 | # landing page |
| 24 | url(r'^landing/$', 'landing', name='landing'), | ||
| 25 | |||
| 24 | url(r'^builds/$', 'builds', name='all-builds'), | 26 | url(r'^builds/$', 'builds', name='all-builds'), |
| 25 | # build info navigation | 27 | # build info navigation |
| 26 | url(r'^build/(?P<build_id>\d+)$', 'builddashboard', name="builddashboard"), | 28 | url(r'^build/(?P<build_id>\d+)$', 'builddashboard', name="builddashboard"), |
| @@ -74,6 +76,7 @@ urlpatterns = patterns('toastergui.views', | |||
| 74 | url(r'^targets/$', 'targets', name='targets'), | 76 | url(r'^targets/$', 'targets', name='targets'), |
| 75 | url(r'^machines/$', 'machines', name='machines'), | 77 | url(r'^machines/$', 'machines', name='machines'), |
| 76 | 78 | ||
| 79 | url(r'^projects/$', 'projects', name='all-projects'), | ||
| 77 | url(r'^project/(?P<pid>\d+)/$', 'project', name='project'), | 80 | url(r'^project/(?P<pid>\d+)/$', 'project', name='project'), |
| 78 | url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'), | 81 | url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'), |
| 79 | url(r'^project/(?P<pid>\d+)/builds$', 'projectbuilds', name='projectbuilds'), | 82 | url(r'^project/(?P<pid>\d+)/builds$', 'projectbuilds', name='projectbuilds'), |
| @@ -85,5 +88,5 @@ urlpatterns = patterns('toastergui.views', | |||
| 85 | 88 | ||
| 86 | 89 | ||
| 87 | # default redirection | 90 | # default redirection |
| 88 | url(r'^$', RedirectView.as_view( url= 'builds/')), | 91 | url(r'^$', RedirectView.as_view( url= 'landing')), |
| 89 | ) | 92 | ) |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 66113cfdf3..38d67e378f 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -38,6 +38,51 @@ from datetime import timedelta | |||
| 38 | from django.utils import formats | 38 | from django.utils import formats |
| 39 | import json | 39 | import json |
| 40 | 40 | ||
| 41 | |||
| 42 | # all new sessions should come through the landing page; | ||
| 43 | # determine in which mode we are running in, and redirect appropriately | ||
| 44 | def landing(request): | ||
| 45 | if toastermain.settings.MANAGED and Build.objects.count() == 0 and Project.objects.count() > 0: | ||
| 46 | return redirect(reverse('all-projects'), permanent = False) | ||
| 47 | |||
| 48 | if Build.objects.all().count() > 0: | ||
| 49 | return redirect(reverse('all-builds'), permanent = False) | ||
| 50 | |||
| 51 | return render(request, 'landing.html') | ||
| 52 | |||
| 53 | def _project_recent_build_list(prj): | ||
| 54 | # build requests not yet started | ||
| 55 | return (map(lambda x: { | ||
| 56 | "id": x.pk, | ||
| 57 | "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()), | ||
| 58 | "status": x.get_state_display(), | ||
| 59 | }, prj.buildrequest_set.filter(state__lt = BuildRequest.REQ_INPROGRESS).order_by("-pk")) + | ||
| 60 | # build requests started, but with no build yet | ||
| 61 | map(lambda x: { | ||
| 62 | "id": x.pk, | ||
| 63 | "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()), | ||
| 64 | "status": x.get_state_display(), | ||
| 65 | }, prj.buildrequest_set.filter(state = BuildRequest.REQ_INPROGRESS, build = None).order_by("-pk")) + | ||
| 66 | # build requests that failed | ||
| 67 | map(lambda x: { | ||
| 68 | "id": x.pk, | ||
| 69 | "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()), | ||
| 70 | "status": x.get_state_display(), | ||
| 71 | "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()), | ||
| 72 | }, prj.buildrequest_set.filter(state = BuildRequest.REQ_FAILED).order_by("-pk")) + | ||
| 73 | # and already made builds | ||
| 74 | map(lambda x: { | ||
| 75 | "id": x.pk, | ||
| 76 | "targets": map(lambda y: {"target": y.target }, x.target_set.all()), | ||
| 77 | "status": x.get_outcome_display(), | ||
| 78 | "completed_on" : x.completed_on.strftime('%s')+"000", | ||
| 79 | "build_time" : (x.completed_on - x.started_on).total_seconds(), | ||
| 80 | "build_page_url" : reverse('builddashboard', args=(x.pk,)), | ||
| 81 | "completeper": x.completeper(), | ||
| 82 | "eta": x.eta().ctime(), | ||
| 83 | }, prj.build_set.all())) | ||
| 84 | |||
| 85 | |||
| 41 | def _build_page_range(paginator, index = 1): | 86 | def _build_page_range(paginator, index = 1): |
| 42 | try: | 87 | try: |
| 43 | page = paginator.page(index) | 88 | page = paginator.page(index) |
| @@ -219,6 +264,8 @@ def _save_parameters_cookies(response, pagesize, orderby, request): | |||
| 219 | response.set_cookie(key='orderby', value=html_parser.unescape(orderby), path=request.path) | 264 | response.set_cookie(key='orderby', value=html_parser.unescape(orderby), path=request.path) |
| 220 | return response | 265 | return response |
| 221 | 266 | ||
| 267 | |||
| 268 | |||
| 222 | # shows the "all builds" page | 269 | # shows the "all builds" page |
| 223 | def builds(request): | 270 | def builds(request): |
| 224 | template = 'build.html' | 271 | template = 'build.html' |
| @@ -242,7 +289,7 @@ def builds(request): | |||
| 242 | build_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) | 289 | build_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) |
| 243 | 290 | ||
| 244 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) | 291 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) |
| 245 | build_mru = Build.objects.filter(completed_on__gte=(timezone.now()-timedelta(hours=24))).order_by("-started_on")[:3] | 292 | build_mru = Build.objects.order_by("-started_on")[:3] |
| 246 | 293 | ||
| 247 | # set up list of fstypes for each build | 294 | # set up list of fstypes for each build |
| 248 | fstypes_map = {}; | 295 | fstypes_map = {}; |
| @@ -2553,6 +2600,84 @@ if toastermain.settings.MANAGED: | |||
| 2553 | } | 2600 | } |
| 2554 | 2601 | ||
| 2555 | return render(request, template, context) | 2602 | return render(request, template, context) |
| 2603 | |||
| 2604 | |||
| 2605 | |||
| 2606 | def projects(request): | ||
| 2607 | template="projects.html" | ||
| 2608 | |||
| 2609 | (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-') | ||
| 2610 | mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } | ||
| 2611 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
| 2612 | if retval: | ||
| 2613 | return _redirect_parameters( 'all-projects', request.GET, mandatory_parameters) | ||
| 2614 | |||
| 2615 | queryset_all = Project.objects.all() | ||
| 2616 | |||
| 2617 | # boilerplate code that takes a request for an object type and returns a queryset | ||
| 2618 | # for that object type. copypasta for all needed table searches | ||
| 2619 | (filter_string, search_term, ordering_string) = _search_tuple(request, Project) | ||
| 2620 | queryset_with_search = _get_queryset(Project, queryset_all, None, search_term, ordering_string, 'updated:-') | ||
| 2621 | queryset = _get_queryset(Project, queryset_all, filter_string, search_term, ordering_string, 'updated:-') | ||
| 2622 | |||
| 2623 | # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display | ||
| 2624 | project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) | ||
| 2625 | |||
| 2626 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) | ||
| 2627 | build_mru = Build.objects.order_by("-started_on")[:3] | ||
| 2628 | |||
| 2629 | |||
| 2630 | |||
| 2631 | context = { | ||
| 2632 | 'mru' : build_mru, | ||
| 2633 | |||
| 2634 | 'objects' : project_info, | ||
| 2635 | 'objectname' : "projects", | ||
| 2636 | 'default_orderby' : 'id:-', | ||
| 2637 | 'search_term' : search_term, | ||
| 2638 | 'total_count' : queryset_with_search.count(), | ||
| 2639 | 'tablecols': [ | ||
| 2640 | {'name': 'Project', | ||
| 2641 | 'orderfield': _get_toggle_order(request, "name"), | ||
| 2642 | 'ordericon':_get_toggle_order_icon(request, "name"), | ||
| 2643 | 'orderkey' : 'name', | ||
| 2644 | }, | ||
| 2645 | {'name': 'Release', | ||
| 2646 | 'qhelp' : "The version of the build system used by the project", | ||
| 2647 | 'orderfield': _get_toggle_order(request, "release__name"), | ||
| 2648 | 'ordericon':_get_toggle_order_icon(request, "release__name"), | ||
| 2649 | 'orderkey' : 'release__name', | ||
| 2650 | }, | ||
| 2651 | {'name': 'Machine', | ||
| 2652 | 'qhelp': "The hardware currently selected for the project", | ||
| 2653 | }, | ||
| 2654 | {'name': 'Number of builds', | ||
| 2655 | 'qhelp': "How many builds have been run for the project", | ||
| 2656 | }, | ||
| 2657 | {'name': 'Last outcome', 'clclass': 'loutcome', | ||
| 2658 | 'qhelp': "Tells you if the last project build completed successfully or failed", | ||
| 2659 | }, | ||
| 2660 | {'name': 'Last target', 'clclass': 'ltarget', | ||
| 2661 | 'qhelp': "The last project build target(s): one or more recipes or image recipes", | ||
| 2662 | }, | ||
| 2663 | {'name': 'Last errors', 'clclass': 'lerrors', | ||
| 2664 | 'qhelp': "How many errors were encountered during the last project build (if any)", | ||
| 2665 | }, | ||
| 2666 | {'name': 'Last warnings', 'clclass': 'lwarnings', | ||
| 2667 | 'qhelp': "How many warnigns were encountered during the last project build (if any)", | ||
| 2668 | }, | ||
| 2669 | {'name': 'Last image files', 'clclass': 'limagefiles', 'hidden': 1, | ||
| 2670 | 'qhelp': "The root file system types produced by the last project build", | ||
| 2671 | }, | ||
| 2672 | {'name': 'Last updated', 'clclass': 'updated', | ||
| 2673 | 'orderfield': _get_toggle_order(request, "updated"), | ||
| 2674 | 'ordericon':_get_toggle_order_icon(request, "updated"), | ||
| 2675 | 'orderkey' : 'updated', | ||
| 2676 | } | ||
| 2677 | ] | ||
| 2678 | } | ||
| 2679 | return render(request, template, context) | ||
| 2680 | |||
| 2556 | else: | 2681 | else: |
| 2557 | # these are pages that are NOT available in interactive mode | 2682 | # these are pages that are NOT available in interactive mode |
| 2558 | def managedcontextprocessor(request): | 2683 | def managedcontextprocessor(request): |
| @@ -2599,3 +2724,6 @@ else: | |||
| 2599 | 2724 | ||
| 2600 | def projectbuilds(request): | 2725 | def projectbuilds(request): |
| 2601 | raise Exception("page not available in interactive mode") | 2726 | raise Exception("page not available in interactive mode") |
| 2727 | |||
| 2728 | def projects(request): | ||
| 2729 | raise Exception("page not available in interactive mode") | ||
