aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/toaster/toastergui/templates/basetable_top.html2
-rw-r--r--lib/toaster/toastergui/templates/basetable_top_buildprojects.html16
-rw-r--r--lib/toaster/toastergui/templates/basetable_top_projectbuilds.html16
-rw-r--r--lib/toaster/toastergui/templates/build.html78
-rw-r--r--lib/toaster/toastergui/templates/landing.html66
-rw-r--r--lib/toaster/toastergui/templates/mrb_section.html102
-rw-r--r--lib/toaster/toastergui/templates/projects.html36
-rw-r--r--lib/toaster/toastergui/templatetags/projecttags.py11
-rw-r--r--lib/toaster/toastergui/urls.py5
-rwxr-xr-xlib/toaster/toastergui/views.py130
10 files changed, 384 insertions, 78 deletions
diff --git a/lib/toaster/toastergui/templates/basetable_top.html b/lib/toaster/toastergui/templates/basetable_top.html
index e3f6a4ee2..92a3b5080 100644
--- a/lib/toaster/toastergui/templates/basetable_top.html
+++ b/lib/toaster/toastergui/templates/basetable_top.html
@@ -175,8 +175,8 @@
<button class="btn" type="submit" value="Search">Search</button>
</form>
<div class="pull-right">
+ {% block custombuttons%} {% endblock %}
{% if tablecols %}
- {% block custombuttons%} {% endblock %}
<div class="btn-group">
<button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns
<span class="caret"></span>
diff --git a/lib/toaster/toastergui/templates/basetable_top_buildprojects.html b/lib/toaster/toastergui/templates/basetable_top_buildprojects.html
new file mode 100644
index 000000000..d51717959
--- /dev/null
+++ b/lib/toaster/toastergui/templates/basetable_top_buildprojects.html
@@ -0,0 +1,16 @@
+{% extends "basetable_top.html" %}
+
+{%block custombuttons %}
+{% if MANAGED %}
+ <div class="btn-group builds-projects">
+ <button class="btn dropdown-toggle" data-toggle="dropdown">
+ <span class="selection">Show all builds</span>
+ <i class="icon-caret-down"></i>
+ </button>
+ <ul class="dropdown-menu">
+ <li><a href="{% url 'all-builds'%}">Show all builds</a></li>
+ <li><a href="{% url 'all-projects'%}">Show all projects</a></li>
+ </ul>
+ </div>
+{% endif %}
+{%endblock%}
diff --git a/lib/toaster/toastergui/templates/basetable_top_projectbuilds.html b/lib/toaster/toastergui/templates/basetable_top_projectbuilds.html
new file mode 100644
index 000000000..bfefff5e3
--- /dev/null
+++ b/lib/toaster/toastergui/templates/basetable_top_projectbuilds.html
@@ -0,0 +1,16 @@
+{% extends "basetable_top.html" %}
+
+{%block custombuttons %}
+{% if MANAGED %}
+ <div class="btn-group builds-projects">
+ <button class="btn dropdown-toggle" data-toggle="dropdown">
+ <span class="selection">Show all projects</span>
+ <i class="icon-caret-down"></i>
+ </button>
+ <ul class="dropdown-menu">
+ <li><a href="{% url 'all-builds'%}">Show all builds</a></li>
+ <li><a href="{% url 'all-projects'%}">Show all projects</a></li>
+ </ul>
+ </div>
+{% endif %}
+{%endblock%}
diff --git a/lib/toaster/toastergui/templates/build.html b/lib/toaster/toastergui/templates/build.html
index bef1f1539..f20f04174 100644
--- a/lib/toaster/toastergui/templates/build.html
+++ b/lib/toaster/toastergui/templates/build.html
@@ -6,83 +6,11 @@
{% block pagecontent %}
<div class="row-fluid">
- {% if not objects.paginator.count and not request.GET.filter and not request.GET.search %}
- <!-- Empty - no data in database -->
- <div class="hero-unit span12">
- <button type="button" class="close" data-dismiss="alert">&times;</button>
- <div class="row-fluid">
- <div class="span6">
- <h1>This is Toaster</h1>
- <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>
- <p class="hero-actions">
- <a class="btn btn-primary btn-large" href="https://www.yoctoproject.org/documentation/toaster-manual">Show me the manual</a>
- <a class="btn btn-large" href="https://wiki.yoctoproject.org/wiki/Contribute_to_Toaster">I want to contribute</a>
- </p>
- </div>
- <div class="span5">
- <a href="http://www.yoctoproject.org"><img src="{% static 'img/toaster.png' %}" class="thumbnail" alt="Yocto Project"/> </a>
- </div>
- </div>
- </div>
- {% endif %}
- {%if mru.count > 0%}
- <div class="page-header top-air">
- <h1>
- Recent Builds
- </h1>
- </div>
- {% 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">
- <div class="lead span5">
- {%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%}
- {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
- <a href="{%url 'builddashboard' build.pk%}" class="{%if build.outcome == build.SUCCEEDED %}success{%else%}error{%endif%}">
- {% endif %}
- <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>
- {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
- </a>
- {% endif %}
- </div>
- {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
- <div class="span2 lead">
- {% if build.errors_no %}
- <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>
- {% endif %}
- </div>
- <div class="span2 lead">
- {% if build.warnings_no %}
- <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>
- {% endif %}
- </div>
- <div class="lead pull-right">
- Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a>
- </div>
- {%endif%}{%if build.outcome == build.IN_PROGRESS %}
- <div class="span4">
- <div class="progress" style="margin-top:5px;" data-toggle="tooltip" title="{{build.completeper}}% of tasks complete">
- <div style="width: {{build.completeper}}%;" class="bar"></div>
- </div>
- </div>
- <div class="lead pull-right">ETA: in {{build.eta|naturaltime}}</div>
- {%endif%}
- </div>
- </div>
+ {% include "mrb_section.html" %}
- {% endfor %}{%endif%}
- {% if not objects.paginator.count and not request.GET.filter and not request.GET.search %}
- <!-- Empty - no data in database -->
- {% if mru.count == 0 %}
- <div class="page-header top-air">
- <h1>All builds</h1>
- </div>
- <div class="alert alert-info lead">
- 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>
- </div>
- {% endif %}
- {% else %}
+ {% if 1 %}
<div class="page-header top-air">
<h1>
{% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %}
@@ -108,7 +36,7 @@
{% else %}
- {% include "basetable_top.html" %}
+ {% include "basetable_top_buildprojects.html" %}
<!-- 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 -->
{% for build in objects %}
<tr class="data">
diff --git a/lib/toaster/toastergui/templates/landing.html b/lib/toaster/toastergui/templates/landing.html
new file mode 100644
index 000000000..071edf86e
--- /dev/null
+++ b/lib/toaster/toastergui/templates/landing.html
@@ -0,0 +1,66 @@
+{% extends "base.html" %}
+
+{% load static %}
+{% load projecttags %}
+{% load humanize %}
+
+{% block pagecontent %}
+
+ <div class="container-fluid">
+ <div class="row-fluid">
+ <!-- Empty - no data in database -->
+ <div class="hero-unit span12">
+ <button class="close" data-dismiss="alert" type="button">
+ ×
+ </button>
+ <div class="row-fluid">
+ <div class="span6">
+ <h1>
+ This is Toaster
+ </h1>
+ <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>
+ <p class="hero-actions">
+ <a class="btn btn-primary btn-large" href="https://www.yoctoproject.org/documentation/toaster-manual">
+ Show me the manual
+ </a>
+ <a class="btn btn-large" href="https://wiki.yoctoproject.org/wiki/Contribute_to_Toaster">
+ I want to contribute
+ </a>
+ </p>
+ </div>
+ <div class="span5">
+ <a href="http://www.yoctoproject.org">
+ <img alt="Yocto Project" class="thumbnail" src="/static/img/toaster.png"/>
+ </a>
+ </div>
+ </div>
+ </div>
+ <!-- Empty - no data in database -->
+ <div class="page-header top-air">
+ <h1>
+ All builds
+ </h1>
+ </div>
+ <div class="alert alert-info lead">
+ 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>
+ </div>
+ </div>
+
+{% endblock %}
diff --git a/lib/toaster/toastergui/templates/mrb_section.html b/lib/toaster/toastergui/templates/mrb_section.html
new file mode 100644
index 000000000..5ba0b0849
--- /dev/null
+++ b/lib/toaster/toastergui/templates/mrb_section.html
@@ -0,0 +1,102 @@
+{% load static %}
+{% load projecttags %}
+{% load humanize %}
+
+
+{%if mru.count > 0%}
+
+ <div class="page-header top-air">
+ <h1>
+ Latest Builds
+ </h1>
+ </div>
+ <div id="latest-builds">
+ {% 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%}" style="padding-top: 0;">
+ {% if build.project %}
+ <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>
+ {% endif %}
+
+ <div class="row-fluid">
+ <div class="span4 lead">
+ {%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%}
+ {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
+ <a href="{%url 'builddashboard' build.pk%}" class="{%if build.outcome == build.SUCCEEDED %}success{%else%}error{%endif%}">
+ {% endif %}
+ <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>
+ {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
+ </a>
+ {% endif %}
+ </div>
+ {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
+ <div class="span2 lead">
+ {% if build.errors_no %}
+ <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>
+ {% endif %}
+ </div>
+ <div class="span2 lead">
+ {% if build.warnings_no %}
+ <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>
+ {% endif %}
+ </div>
+ <div class="lead ">
+ <span class="lead{%if not build.project%} pull-right{%endif%}">
+ Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a>
+ </span>
+ {% if build.project %}
+ <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>
+ {% endif %}
+ </div>
+ {%endif%}
+ {%if build.outcome == build.IN_PROGRESS %}
+ <div class="span4">
+ <div class="progress" style="margin-top:5px;" data-toggle="tooltip" title="{{build.completeper}}% of tasks complete">
+ <div style="width: {{build.completeper}}%;" class="bar"></div>
+ </div>
+ </div>
+ <div class="lead pull-right">ETA: in {{build.eta|naturaltime}}</div>
+ {%endif%}
+ </div>
+ </div>
+
+ {% endfor %}
+ </div>
+
+<script>
+
+function _makeXHRBuildCall(data, onsuccess, onfail) {
+ $.ajax( {
+ type: "POST",
+ url: "{% url 'xhr_projectbuild' project.id %}",
+ data: data,
+ headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
+ success: function (_data) {
+ if (_data.error != "ok") {
+ alert(_data.error);
+ } else {
+ if (onsuccess != undefined) onsuccess(_data);
+ }
+ },
+ error: function (_data) {
+ alert("Call failed");
+ console.log(_data);
+ if (onfail) onfail(data);
+ }
+ });
+}
+
+
+function scheduleBuild(projectName, buildlist) {
+ console.log("scheduleBuild");
+// _makeXHRBuildCall({targets: buildlist.join(" ")}, function (_data) {
+
+ $('#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">' +
+ '<div class="span4 lead">' + buildlist.join(" ") +
+ '</div><div class="span4 lead pull-right">Build queued. Your build will start shortly.</div></div></div>');
+// }
+}
+
+</script>
+
+{%endif%}
+
diff --git a/lib/toaster/toastergui/templates/projects.html b/lib/toaster/toastergui/templates/projects.html
new file mode 100644
index 000000000..432f025d3
--- /dev/null
+++ b/lib/toaster/toastergui/templates/projects.html
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% load static %}
+{% load projecttags %}
+{% load humanize %}
+
+{% block pagecontent %}
+
+
+ {% include "mrb_section.html" %}
+
+
+ <div class="page-header top-air">
+ <h1>
+ All projects
+ </h1>
+ </div>
+
+{% include "basetable_top_projectbuilds.html" %}
+ {% for o in objects %}
+ <tr class="data">
+ <td><a href="{% url 'project' o.id %}">{{o.name}}</a></td>
+ <td><a href="{% url 'project' o.id %}">{{o.release.name}}</a></td>
+ <td>{{o.get_current_machine_name}}</td>
+ <td>{{o.get_number_of_builds}}</td>
+ <td>{{o.get_last_outcome}}</td>
+ <td>{{o.get_last_target}}</td>
+ <td>{{o.get_last_errors}}</td>
+ <td>{{o.get_last_warnings}}</td>
+ <td>{{o.get_last_imgfiles}}</td>
+ <td>{{o.updated|date:"d/m/y H:i"}}</td>
+ </tr>
+ {% endfor %}
+{% include "basetable_bottom.html" %}
+
+{% endblock %}
diff --git a/lib/toaster/toastergui/templatetags/projecttags.py b/lib/toaster/toastergui/templatetags/projecttags.py
index b953aa158..4a97eb7ac 100644
--- a/lib/toaster/toastergui/templatetags/projecttags.py
+++ b/lib/toaster/toastergui/templatetags/projecttags.py
@@ -24,6 +24,7 @@ import re
from django import template
from django.utils import timezone
from django.template.defaultfilters import filesizeformat
+import json as JsonLib
register = template.Library()
@@ -40,6 +41,16 @@ def sectohms(time):
hours = int(tdsec / 3600)
return "%02d:%02d:%02d" % (hours, int((tdsec - (hours * 3600))/ 60), int(tdsec) % 60)
+
+@register.filter(name = 'mapselect')
+def mapselect(value, argument):
+ return map(lambda x: vars(x)[argument], value)
+
+
+@register.filter(name = "json")
+def json(value):
+ return JsonLib.dumps(value)
+
@register.assignment_tag
def query(qs, **kwargs):
""" template tag which allows queryset filtering. Usage:
diff --git a/lib/toaster/toastergui/urls.py b/lib/toaster/toastergui/urls.py
index e642e3203..07821b603 100644
--- a/lib/toaster/toastergui/urls.py
+++ b/lib/toaster/toastergui/urls.py
@@ -21,6 +21,8 @@ from django.views.generic import RedirectView
urlpatterns = patterns('toastergui.views',
# landing page
+ url(r'^landing/$', 'landing', name='landing'),
+
url(r'^builds/$', 'builds', name='all-builds'),
# build info navigation
url(r'^build/(?P<build_id>\d+)$', 'builddashboard', name="builddashboard"),
@@ -74,6 +76,7 @@ urlpatterns = patterns('toastergui.views',
url(r'^targets/$', 'targets', name='targets'),
url(r'^machines/$', 'machines', name='machines'),
+ url(r'^projects/$', 'projects', name='all-projects'),
url(r'^project/(?P<pid>\d+)/$', 'project', name='project'),
url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'),
url(r'^project/(?P<pid>\d+)/builds$', 'projectbuilds', name='projectbuilds'),
@@ -85,5 +88,5 @@ urlpatterns = patterns('toastergui.views',
# default redirection
- url(r'^$', RedirectView.as_view( url= 'builds/')),
+ url(r'^$', RedirectView.as_view( url= 'landing')),
)
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 66113cfdf..38d67e378 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -38,6 +38,51 @@ from datetime import timedelta
from django.utils import formats
import json
+
+# all new sessions should come through the landing page;
+# determine in which mode we are running in, and redirect appropriately
+def landing(request):
+ if toastermain.settings.MANAGED and Build.objects.count() == 0 and Project.objects.count() > 0:
+ return redirect(reverse('all-projects'), permanent = False)
+
+ if Build.objects.all().count() > 0:
+ return redirect(reverse('all-builds'), permanent = False)
+
+ return render(request, 'landing.html')
+
+def _project_recent_build_list(prj):
+ # build requests not yet started
+ return (map(lambda x: {
+ "id": x.pk,
+ "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
+ "status": x.get_state_display(),
+ }, prj.buildrequest_set.filter(state__lt = BuildRequest.REQ_INPROGRESS).order_by("-pk")) +
+ # build requests started, but with no build yet
+ map(lambda x: {
+ "id": x.pk,
+ "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
+ "status": x.get_state_display(),
+ }, prj.buildrequest_set.filter(state = BuildRequest.REQ_INPROGRESS, build = None).order_by("-pk")) +
+ # build requests that failed
+ map(lambda x: {
+ "id": x.pk,
+ "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
+ "status": x.get_state_display(),
+ "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()),
+ }, prj.buildrequest_set.filter(state = BuildRequest.REQ_FAILED).order_by("-pk")) +
+ # and already made builds
+ map(lambda x: {
+ "id": x.pk,
+ "targets": map(lambda y: {"target": y.target }, x.target_set.all()),
+ "status": x.get_outcome_display(),
+ "completed_on" : x.completed_on.strftime('%s')+"000",
+ "build_time" : (x.completed_on - x.started_on).total_seconds(),
+ "build_page_url" : reverse('builddashboard', args=(x.pk,)),
+ "completeper": x.completeper(),
+ "eta": x.eta().ctime(),
+ }, prj.build_set.all()))
+
+
def _build_page_range(paginator, index = 1):
try:
page = paginator.page(index)
@@ -219,6 +264,8 @@ def _save_parameters_cookies(response, pagesize, orderby, request):
response.set_cookie(key='orderby', value=html_parser.unescape(orderby), path=request.path)
return response
+
+
# shows the "all builds" page
def builds(request):
template = 'build.html'
@@ -242,7 +289,7 @@ def builds(request):
build_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1))
# build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds)
- build_mru = Build.objects.filter(completed_on__gte=(timezone.now()-timedelta(hours=24))).order_by("-started_on")[:3]
+ build_mru = Build.objects.order_by("-started_on")[:3]
# set up list of fstypes for each build
fstypes_map = {};
@@ -2553,6 +2600,84 @@ if toastermain.settings.MANAGED:
}
return render(request, template, context)
+
+
+
+ def projects(request):
+ template="projects.html"
+
+ (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-')
+ mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
+ retval = _verify_parameters( request.GET, mandatory_parameters )
+ if retval:
+ return _redirect_parameters( 'all-projects', request.GET, mandatory_parameters)
+
+ queryset_all = Project.objects.all()
+
+ # boilerplate code that takes a request for an object type and returns a queryset
+ # for that object type. copypasta for all needed table searches
+ (filter_string, search_term, ordering_string) = _search_tuple(request, Project)
+ queryset_with_search = _get_queryset(Project, queryset_all, None, search_term, ordering_string, 'updated:-')
+ queryset = _get_queryset(Project, queryset_all, filter_string, search_term, ordering_string, 'updated:-')
+
+ # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display
+ project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1))
+
+ # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds)
+ build_mru = Build.objects.order_by("-started_on")[:3]
+
+
+
+ context = {
+ 'mru' : build_mru,
+
+ 'objects' : project_info,
+ 'objectname' : "projects",
+ 'default_orderby' : 'id:-',
+ 'search_term' : search_term,
+ 'total_count' : queryset_with_search.count(),
+ 'tablecols': [
+ {'name': 'Project',
+ 'orderfield': _get_toggle_order(request, "name"),
+ 'ordericon':_get_toggle_order_icon(request, "name"),
+ 'orderkey' : 'name',
+ },
+ {'name': 'Release',
+ 'qhelp' : "The version of the build system used by the project",
+ 'orderfield': _get_toggle_order(request, "release__name"),
+ 'ordericon':_get_toggle_order_icon(request, "release__name"),
+ 'orderkey' : 'release__name',
+ },
+ {'name': 'Machine',
+ 'qhelp': "The hardware currently selected for the project",
+ },
+ {'name': 'Number of builds',
+ 'qhelp': "How many builds have been run for the project",
+ },
+ {'name': 'Last outcome', 'clclass': 'loutcome',
+ 'qhelp': "Tells you if the last project build completed successfully or failed",
+ },
+ {'name': 'Last target', 'clclass': 'ltarget',
+ 'qhelp': "The last project build target(s): one or more recipes or image recipes",
+ },
+ {'name': 'Last errors', 'clclass': 'lerrors',
+ 'qhelp': "How many errors were encountered during the last project build (if any)",
+ },
+ {'name': 'Last warnings', 'clclass': 'lwarnings',
+ 'qhelp': "How many warnigns were encountered during the last project build (if any)",
+ },
+ {'name': 'Last image files', 'clclass': 'limagefiles', 'hidden': 1,
+ 'qhelp': "The root file system types produced by the last project build",
+ },
+ {'name': 'Last updated', 'clclass': 'updated',
+ 'orderfield': _get_toggle_order(request, "updated"),
+ 'ordericon':_get_toggle_order_icon(request, "updated"),
+ 'orderkey' : 'updated',
+ }
+ ]
+ }
+ return render(request, template, context)
+
else:
# these are pages that are NOT available in interactive mode
def managedcontextprocessor(request):
@@ -2599,3 +2724,6 @@ else:
def projectbuilds(request):
raise Exception("page not available in interactive mode")
+
+ def projects(request):
+ raise Exception("page not available in interactive mode")