diff options
Diffstat (limited to 'bitbake/lib')
15 files changed, 471 insertions, 303 deletions
diff --git a/bitbake/lib/toaster/bldcontrol/migrations/0005_reorder_buildrequest_states.py b/bitbake/lib/toaster/bldcontrol/migrations/0005_reorder_buildrequest_states.py new file mode 100644 index 0000000000..4bb9517768 --- /dev/null +++ b/bitbake/lib/toaster/bldcontrol/migrations/0005_reorder_buildrequest_states.py | |||
@@ -0,0 +1,19 @@ | |||
1 | # -*- coding: utf-8 -*- | ||
2 | from __future__ import unicode_literals | ||
3 | |||
4 | from django.db import migrations, models | ||
5 | |||
6 | |||
7 | class Migration(migrations.Migration): | ||
8 | |||
9 | dependencies = [ | ||
10 | ('bldcontrol', '0004_auto_20160523_1446'), | ||
11 | ] | ||
12 | |||
13 | operations = [ | ||
14 | migrations.AlterField( | ||
15 | model_name='buildrequest', | ||
16 | name='state', | ||
17 | field=models.IntegerField(choices=[(0, 'created'), (1, 'queued'), (2, 'in progress'), (3, 'failed'), (4, 'deleted'), (5, 'cancelling'), (6, 'completed'), (7, 'archive')], default=0), | ||
18 | ), | ||
19 | ] | ||
diff --git a/bitbake/lib/toaster/bldcontrol/models.py b/bitbake/lib/toaster/bldcontrol/models.py index f06c562a38..f055480686 100644 --- a/bitbake/lib/toaster/bldcontrol/models.py +++ b/bitbake/lib/toaster/bldcontrol/models.py | |||
@@ -63,20 +63,20 @@ class BuildRequest(models.Model): | |||
63 | REQ_CREATED = 0 | 63 | REQ_CREATED = 0 |
64 | REQ_QUEUED = 1 | 64 | REQ_QUEUED = 1 |
65 | REQ_INPROGRESS = 2 | 65 | REQ_INPROGRESS = 2 |
66 | REQ_COMPLETED = 3 | 66 | REQ_FAILED = 3 |
67 | REQ_FAILED = 4 | 67 | REQ_DELETED = 4 |
68 | REQ_DELETED = 5 | 68 | REQ_CANCELLING = 5 |
69 | REQ_CANCELLING = 6 | 69 | REQ_COMPLETED = 6 |
70 | REQ_ARCHIVE = 7 | 70 | REQ_ARCHIVE = 7 |
71 | 71 | ||
72 | REQUEST_STATE = ( | 72 | REQUEST_STATE = ( |
73 | (REQ_CREATED, "created"), | 73 | (REQ_CREATED, "created"), |
74 | (REQ_QUEUED, "queued"), | 74 | (REQ_QUEUED, "queued"), |
75 | (REQ_INPROGRESS, "in progress"), | 75 | (REQ_INPROGRESS, "in progress"), |
76 | (REQ_COMPLETED, "completed"), | ||
77 | (REQ_FAILED, "failed"), | 76 | (REQ_FAILED, "failed"), |
78 | (REQ_DELETED, "deleted"), | 77 | (REQ_DELETED, "deleted"), |
79 | (REQ_CANCELLING, "cancelling"), | 78 | (REQ_CANCELLING, "cancelling"), |
79 | (REQ_COMPLETED, "completed"), | ||
80 | (REQ_ARCHIVE, "archive"), | 80 | (REQ_ARCHIVE, "archive"), |
81 | ) | 81 | ) |
82 | 82 | ||
@@ -91,7 +91,7 @@ class BuildRequest(models.Model): | |||
91 | 91 | ||
92 | def __init__(self, *args, **kwargs): | 92 | def __init__(self, *args, **kwargs): |
93 | super(BuildRequest, self).__init__(*args, **kwargs) | 93 | super(BuildRequest, self).__init__(*args, **kwargs) |
94 | # Save the old state incase it's about to be modified | 94 | # Save the old state in case it's about to be modified |
95 | self.old_state = self.state | 95 | self.old_state = self.state |
96 | 96 | ||
97 | def save(self, *args, **kwargs): | 97 | def save(self, *args, **kwargs): |
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py index caacc2a544..2df6d4910a 100644 --- a/bitbake/lib/toaster/orm/models.py +++ b/bitbake/lib/toaster/orm/models.py | |||
@@ -592,22 +592,42 @@ class Build(models.Model): | |||
592 | 592 | ||
593 | return target_labels | 593 | return target_labels |
594 | 594 | ||
595 | def get_current_status(self): | 595 | def get_buildrequest(self): |
596 | """ | 596 | buildrequest = None |
597 | get the status string from the build request if the build | 597 | if hasattr(self, 'buildrequest'): |
598 | has one, or the text for the build outcome if it doesn't | 598 | buildrequest = self.buildrequest |
599 | """ | 599 | return buildrequest |
600 | 600 | ||
601 | def is_queued(self): | ||
601 | from bldcontrol.models import BuildRequest | 602 | from bldcontrol.models import BuildRequest |
603 | buildrequest = self.get_buildrequest() | ||
604 | if buildrequest: | ||
605 | return buildrequest.state == BuildRequest.REQ_QUEUED | ||
606 | else: | ||
607 | return False | ||
602 | 608 | ||
603 | build_request = None | 609 | def is_cancelling(self): |
604 | if hasattr(self, 'buildrequest'): | 610 | from bldcontrol.models import BuildRequest |
605 | build_request = self.buildrequest | 611 | buildrequest = self.get_buildrequest() |
612 | if buildrequest: | ||
613 | return self.outcome == Build.IN_PROGRESS and \ | ||
614 | buildrequest.state == BuildRequest.REQ_CANCELLING | ||
615 | else: | ||
616 | return False | ||
606 | 617 | ||
607 | if (build_request | 618 | def get_state(self): |
608 | and build_request.state != BuildRequest.REQ_INPROGRESS | 619 | """ |
609 | and self.outcome == Build.IN_PROGRESS): | 620 | Get the state of the build; one of 'Succeeded', 'Failed', 'In Progress', |
610 | return self.buildrequest.get_state_display() | 621 | 'Cancelled' (Build outcomes); or 'Queued', 'Cancelling' (states |
622 | dependent on the BuildRequest state). | ||
623 | |||
624 | This works around the fact that we have BuildRequest states as well | ||
625 | as Build states, but really we just want to know the state of the build. | ||
626 | """ | ||
627 | if self.is_cancelling(): | ||
628 | return 'Cancelling'; | ||
629 | elif self.is_queued(): | ||
630 | return 'Queued' | ||
611 | else: | 631 | else: |
612 | return self.get_outcome_text() | 632 | return self.get_outcome_text() |
613 | 633 | ||
diff --git a/bitbake/lib/toaster/tests/browser/test_all_builds_page.py b/bitbake/lib/toaster/tests/browser/test_all_builds_page.py index 5ea6532536..521a280de8 100644 --- a/bitbake/lib/toaster/tests/browser/test_all_builds_page.py +++ b/bitbake/lib/toaster/tests/browser/test_all_builds_page.py | |||
@@ -97,13 +97,13 @@ class TestAllBuildsPage(SeleniumTestCase): | |||
97 | self.get(url) | 97 | self.get(url) |
98 | 98 | ||
99 | # shouldn't see a rebuild button for command-line builds | 99 | # shouldn't see a rebuild button for command-line builds |
100 | selector = 'div[data-latest-build-result="%s"] a.run-again-btn' % default_build.id | 100 | selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % default_build.id |
101 | run_again_button = self.find_all(selector) | 101 | run_again_button = self.find_all(selector) |
102 | self.assertEqual(len(run_again_button), 0, | 102 | self.assertEqual(len(run_again_button), 0, |
103 | 'should not see a rebuild button for cli builds') | 103 | 'should not see a rebuild button for cli builds') |
104 | 104 | ||
105 | # should see a rebuild button for non-command-line builds | 105 | # should see a rebuild button for non-command-line builds |
106 | selector = 'div[data-latest-build-result="%s"] a.run-again-btn' % build1.id | 106 | selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % build1.id |
107 | run_again_button = self.find_all(selector) | 107 | run_again_button = self.find_all(selector) |
108 | self.assertEqual(len(run_again_button), 1, | 108 | self.assertEqual(len(run_again_button), 1, |
109 | 'should see a rebuild button for non-cli builds') | 109 | 'should see a rebuild button for non-cli builds') |
diff --git a/bitbake/lib/toaster/toastergui/api.py b/bitbake/lib/toaster/toastergui/api.py index 414afce1d0..aa3cbd83b2 100644 --- a/bitbake/lib/toaster/toastergui/api.py +++ b/bitbake/lib/toaster/toastergui/api.py | |||
@@ -27,7 +27,10 @@ from bldcontrol import bbcontroller | |||
27 | from django.http import HttpResponse, JsonResponse | 27 | from django.http import HttpResponse, JsonResponse |
28 | from django.views.generic import View | 28 | from django.views.generic import View |
29 | from django.core.urlresolvers import reverse | 29 | from django.core.urlresolvers import reverse |
30 | 30 | from django.core import serializers | |
31 | from django.utils import timezone | ||
32 | from django.template.defaultfilters import date | ||
33 | from toastergui.templatetags.projecttags import json, sectohms, get_tasks | ||
31 | 34 | ||
32 | def error_response(error): | 35 | def error_response(error): |
33 | return JsonResponse({"error": error}) | 36 | return JsonResponse({"error": error}) |
@@ -208,3 +211,103 @@ class XhrLayer(View): | |||
208 | "error": "ok", | 211 | "error": "ok", |
209 | "redirect": reverse('project', args=(kwargs['pid'],)) | 212 | "redirect": reverse('project', args=(kwargs['pid'],)) |
210 | }) | 213 | }) |
214 | |||
215 | class MostRecentBuildsView(View): | ||
216 | def _was_yesterday_or_earlier(self, completed_on): | ||
217 | now = timezone.now() | ||
218 | delta = now - completed_on | ||
219 | |||
220 | if delta.days >= 1: | ||
221 | return True | ||
222 | |||
223 | return False | ||
224 | |||
225 | def get(self, request, *args, **kwargs): | ||
226 | """ | ||
227 | Returns a list of builds in JSON format. | ||
228 | """ | ||
229 | mrb_type = 'all' | ||
230 | project = None | ||
231 | |||
232 | project_id = request.GET.get('project_id', None) | ||
233 | if project_id: | ||
234 | try: | ||
235 | mrb_type = 'project' | ||
236 | project = Project.objects.get(pk=project_id) | ||
237 | except: | ||
238 | # if project lookup fails, assume no project | ||
239 | pass | ||
240 | |||
241 | recent_build_objs = Build.get_recent(project) | ||
242 | recent_builds = [] | ||
243 | |||
244 | # for timezone conversion | ||
245 | tz = timezone.get_current_timezone() | ||
246 | |||
247 | for build_obj in recent_build_objs: | ||
248 | dashboard_url = reverse('builddashboard', args=(build_obj.pk,)) | ||
249 | buildtime_url = reverse('buildtime', args=(build_obj.pk,)) | ||
250 | rebuild_url = \ | ||
251 | reverse('xhr_buildrequest', args=(build_obj.project.pk,)) | ||
252 | cancel_url = \ | ||
253 | reverse('xhr_buildrequest', args=(build_obj.project.pk,)) | ||
254 | |||
255 | build = {} | ||
256 | build['id'] = build_obj.pk | ||
257 | build['dashboard_url'] = dashboard_url | ||
258 | |||
259 | tasks_complete_percentage = 0 | ||
260 | if build_obj.outcome in (Build.SUCCEEDED, Build.FAILED): | ||
261 | tasks_complete_percentage = 100 | ||
262 | elif build_obj.outcome == Build.IN_PROGRESS: | ||
263 | tasks_complete_percentage = build_obj.completeper() | ||
264 | build['tasks_complete_percentage'] = tasks_complete_percentage | ||
265 | |||
266 | build['state'] = build_obj.get_state() | ||
267 | |||
268 | build['errors'] = build_obj.errors.count() | ||
269 | build['dashboard_errors_url'] = dashboard_url + '#errors' | ||
270 | |||
271 | build['warnings'] = build_obj.warnings.count() | ||
272 | build['dashboard_warnings_url'] = dashboard_url + '#warnings' | ||
273 | |||
274 | build['buildtime'] = sectohms(build_obj.timespent_seconds) | ||
275 | build['buildtime_url'] = buildtime_url | ||
276 | |||
277 | build['rebuild_url'] = rebuild_url | ||
278 | build['cancel_url'] = cancel_url | ||
279 | |||
280 | build['is_default_project_build'] = build_obj.project.is_default | ||
281 | |||
282 | build['build_targets_json'] = \ | ||
283 | json(get_tasks(build_obj.target_set.all())) | ||
284 | |||
285 | # convert completed_on time to user's timezone | ||
286 | completed_on = timezone.localtime(build_obj.completed_on) | ||
287 | |||
288 | completed_on_template = '%H:%M' | ||
289 | if self._was_yesterday_or_earlier(completed_on): | ||
290 | completed_on_template = '%d/%m/%Y ' + completed_on_template | ||
291 | build['completed_on'] = completed_on.strftime(completed_on_template) | ||
292 | |||
293 | targets = [] | ||
294 | target_objs = build_obj.get_sorted_target_list() | ||
295 | for target_obj in target_objs: | ||
296 | if target_obj.task: | ||
297 | targets.append(target_obj.target + ':' + target_obj.task) | ||
298 | else: | ||
299 | targets.append(target_obj.target) | ||
300 | build['targets'] = ' '.join(targets) | ||
301 | |||
302 | # abbreviated form of the full target list | ||
303 | abbreviated_targets = '' | ||
304 | num_targets = len(targets) | ||
305 | if num_targets > 0: | ||
306 | abbreviated_targets = targets[0] | ||
307 | if num_targets > 1: | ||
308 | abbreviated_targets += (' +%s' % (num_targets - 1)) | ||
309 | build['targets_abbreviated'] = abbreviated_targets | ||
310 | |||
311 | recent_builds.append(build) | ||
312 | |||
313 | return JsonResponse(recent_builds, safe=False) | ||
diff --git a/bitbake/lib/toaster/toastergui/static/css/default.css b/bitbake/lib/toaster/toastergui/static/css/default.css index 0d3570a21f..3a0fbb82c8 100644 --- a/bitbake/lib/toaster/toastergui/static/css/default.css +++ b/bitbake/lib/toaster/toastergui/static/css/default.css | |||
@@ -45,6 +45,7 @@ img.logo { height: 30px; vertical-align: bottom; } | |||
45 | .alert-link.build-warnings, | 45 | .alert-link.build-warnings, |
46 | .glyphicon-warning-sign.build-warnings { color: #8a6d3b; } | 46 | .glyphicon-warning-sign.build-warnings { color: #8a6d3b; } |
47 | .build-result .project-name { margin-top: -10px; margin-bottom: 5px; } | 47 | .build-result .project-name { margin-top: -10px; margin-bottom: 5px; } |
48 | .rebuild-btn, .cancel-build-btn { cursor: pointer; } | ||
48 | 49 | ||
49 | /* Styles for the help information */ | 50 | /* Styles for the help information */ |
50 | .get-help { color: #CCCCCC; } | 51 | .get-help { color: #CCCCCC; } |
diff --git a/bitbake/lib/toaster/toastergui/static/js/jsrender.min.js b/bitbake/lib/toaster/toastergui/static/js/jsrender.min.js new file mode 100644 index 0000000000..87cac4eb35 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/static/js/jsrender.min.js | |||
@@ -0,0 +1,4 @@ | |||
1 | /*! JsRender v0.9.78 (Beta): http://jsviews.com/#jsrender */ | ||
2 | /*! **VERSION FOR WEB** (For NODE.JS see http://jsviews.com/download/jsrender-node.js) */ | ||
3 | !function(e,t){var n=t.jQuery;"object"==typeof exports?module.exports=n?e(t,n):function(n){if(n&&!n.fn)throw"Provide jQuery or null";return e(t,n)}:"function"==typeof define&&define.amd?define(function(){return e(t)}):e(t,!1)}(function(e,t){"use strict";function n(e,t){return function(){var n,r=this,i=r.base;return r.base=e,n=t.apply(r,arguments),r.base=i,n}}function r(e,t){return te(t)&&(t=n(e?e._d?e:n(s,e):s,t),t._d=1),t}function i(e,t){for(var n in t.props)Re.test(n)&&(e[n]=r(e[n],t.props[n]))}function o(e){return e}function s(){return""}function a(e){try{throw console.log("JsRender dbg breakpoint: "+e),"dbg breakpoint"}catch(t){}return this.base?this.baseApply(arguments):e}function d(e){this.name=(t.link?"JsViews":"JsRender")+" Error",this.message=e||this.name}function u(e,t){for(var n in t)e[n]=t[n];return e}function l(e,t,n){return e?(de.delimiters=[e,t,ve=n?n.charAt(0):ve],pe=e.charAt(0),ce=e.charAt(1),fe=t.charAt(0),ge=t.charAt(1),e="\\"+pe+"(\\"+ve+")?\\"+ce,t="\\"+fe+"\\"+ge,G="(?:(\\w+(?=[\\/\\s\\"+fe+"]))|(\\w+)?(:)|(>)|(\\*))\\s*((?:[^\\"+fe+"]|\\"+fe+"(?!\\"+ge+"))*?)",ae.rTag="(?:"+G+")",G=new RegExp("(?:"+e+G+"(\\/)?|\\"+pe+"(\\"+ve+")?\\"+ce+"(?:(?:\\/(\\w+))\\s*|!--[\\s\\S]*?--))"+t,"g"),W=new RegExp("<.*>|([^\\\\]|^)[{}]|"+e+".*"+t),le):de.delimiters}function p(e,t){t||e===!0||(t=e,e=void 0);var n,r,i,o,s=this,a=!t||"root"===t;if(e){if(o=t&&s.type===t&&s,!o)if(n=s.views,s._.useKey){for(r in n)if(o=t?n[r].get(e,t):n[r])break}else for(r=0,i=n.length;!o&&i>r;r++)o=t?n[r].get(e,t):n[r]}else if(a)for(;s.parent;)o=s,s=s.parent;else for(;s&&!o;)o=s.type===t?s:void 0,s=s.parent;return o}function c(){var e=this.get("item");return e?e.index:void 0}function f(){return this.index}function g(t){var n,r=this,i=r.linkCtx,o=(r.ctx||{})[t];return void 0===o&&i&&i.ctx&&(o=i.ctx[t]),void 0===o&&(o=oe[t]),o&&te(o)&&!o._wrp&&(n=function(){return o.apply(this&&this!==e?this:r,arguments)},n._wrp=r,u(n,o)),n||o}function v(e){return e&&(e.fn?e:this.getRsc("templates",e)||re(e))}function h(e,t,n,r){var o,s,a="number"==typeof n&&t.tmpl.bnds[n-1],d=t.linkCtx;return void 0!==r?n=r={props:{},args:[r]}:a&&(n=a(t.data,t,ae)),s=n.args[0],(e||a)&&(o=d&&d.tag,o||(o=u(new ae._tg,{_:{inline:!d,bnd:a,unlinked:!0},tagName:":",cvt:e,flow:!0,tagCtx:n}),d&&(d.tag=o,o.linkCtx=d),n.ctx=L(n.ctx,(d?d.view:t).ctx)),o._er=r&&s,i(o,n),n.view=t,o.ctx=n.ctx||o.ctx||{},n.ctx=void 0,s=o.cvtArgs("true"!==e&&e)[0],s=a&&t._.onRender?t._.onRender(s,t,o):s),void 0!=s?s:""}function m(e){var t=this,n=t.tagCtx,r=n.view,i=n.args;return e=e||t.convert,e=e&&(""+e===e?r.getRsc("converters",e)||S("Unknown converter: '"+e+"'"):e),i=i.length||n.index?e?i.slice():i:[r.data],e&&(e.depends&&(t.depends=ae.getDeps(t.depends,t,e.depends,e)),i[0]=e.apply(t,i)),i}function w(e,t){for(var n,r,i=this;void 0===n&&i;)r=i.tmpl&&i.tmpl[e],n=r&&r[t],i=i.parent;return n||Y[e][t]}function x(e,t,n,r,o,s){t=t||X;var a,d,u,l,p,c,f,g,v,h,m,w,x,b,_,y,k,j,C,A="",T=t.linkCtx||0,V=t.ctx,R=n||t.tmpl,M="number"==typeof r&&t.tmpl.bnds[r-1];for("tag"===e._is?(a=e,e=a.tagName,r=a.tagCtxs,u=a.template):(d=t.getRsc("tags",e)||S("Unknown tag: {{"+e+"}} "),u=d.template),void 0!==s?(A+=s,r=s=[{props:{},args:[]}]):M&&(r=M(t.data,t,ae)),g=r.length,f=0;g>f;f++)h=r[f],(!T||!T.tag||f&&!T.tag._.inline||a._er)&&((w=R.tmpls&&h.tmpl)&&(w=h.content=R.tmpls[w-1]),h.index=f,h.tmpl=w,h.render=N,h.view=t,h.ctx=L(h.ctx,V)),(n=h.props.tmpl)&&(h.tmpl=t.getTmpl(n)),a||(a=new d._ctr,x=!!a.init,a.parent=c=V&&V.tag,a.tagCtxs=r,C=a.dataMap,T&&(a._.inline=!1,T.tag=a,a.linkCtx=T),(a._.bnd=M||T.fn)?a._.arrVws={}:a.dataBoundOnly&&S("{^{"+e+"}} tag must be data-bound")),r=a.tagCtxs,C=a.dataMap,h.tag=a,C&&r&&(h.map=r[f].map),a.flow||(m=h.ctx=h.ctx||{},l=a.parents=m.parentTags=V&&L(m.parentTags,V.parentTags)||{},c&&(l[c.tagName]=c),l[a.tagName]=m.tag=a);if(!(a._er=s)){for(i(a,r[0]),a.rendering={},f=0;g>f;f++)h=a.tagCtx=r[f],k=h.props,y=a.cvtArgs(),(b=k.dataMap||C)&&(y.length||k.dataMap)&&(_=h.map,_&&_.src===y[0]&&!o||(_&&_.src&&_.unmap(),_=h.map=b.map(y[0],k,void 0,!a._.bnd)),y=[_.tgt]),a.ctx=h.ctx,f||(x&&(j=a.template,a.init(h,T,a.ctx),x=void 0),T&&(T.attr=a.attr=T.attr||a.attr),p=a.attr,a._.noVws=p&&p!==Ee),v=void 0,a.render&&(v=a.render.apply(a,y)),y.length||(y=[t]),void 0===v&&(v=h.render(y[0],!0)||(o?void 0:"")),A=A?A+(v||""):v;a.rendering=void 0}return a.tagCtx=r[0],a.ctx=a.tagCtx.ctx,a._.noVws&&a._.inline&&(A="text"===p?ie.html(A):""),M&&t._.onRender?t._.onRender(A,t,a):A}function b(e,t,n,r,i,o,s,a){var d,u,l,p=this,f="array"===t;p.content=a,p.views=f?[]:{},p.parent=n,p.type=t||"top",p.data=r,p.tmpl=i,l=p._={key:0,useKey:f?0:1,id:""+$e++,onRender:s,bnds:{}},p.linked=!!s,n?(d=n.views,u=n._,u.useKey?(d[l.key="_"+u.useKey++]=p,p.index=Ue,p.getIndex=c):d.length===(l.key=p.index=o)?d.push(p):d.splice(o,0,p),p.ctx=e||n.ctx):p.ctx=e}function _(e){var t,n,r,i,o,s,a;for(t in Oe)if(o=Oe[t],(s=o.compile)&&(n=e[t+"s"]))for(r in n)i=n[r]=s(r,n[r],e,0),i._is=t,i&&(a=ae.onStore[t])&&a(r,i,s)}function y(e,t,n){function i(){var t=this;t._={inline:!0,unlinked:!0},t.tagName=e}var o,s,a,d=new ae._tg;if(te(t)?t={depends:t.depends,render:t}:""+t===t&&(t={template:t}),s=t.baseTag){t.flow=!!t.flow,t.baseTag=s=""+s===s?n&&n.tags[s]||se[s]:s,d=u(d,s);for(a in t)d[a]=r(s[a],t[a])}else d=u(d,t);return void 0!==(o=d.template)&&(d.template=""+o===o?re[o]||re(o):o),d.init!==!1&&((i.prototype=d).constructor=d._ctr=i),n&&(d._parentTmpl=n),d}function k(e){return this.base.apply(this,e)}function j(e,n,r,i){function o(n){var o,a;if(""+n===n||n.nodeType>0&&(s=n)){if(!s)if(/^\.\/[^\\:*?"<>]*$/.test(n))(a=re[e=e||n])?n=a:s=document.getElementById(n);else if(t.fn&&!W.test(n))try{s=t(document).find(n)[0]}catch(d){}s&&(i?n=s.innerHTML:(o=s.getAttribute(Se),o?o!==Ie?(n=re[o],delete re[o]):t.fn&&(n=t.data(s)[Ie]):(e=e||(t.fn?Ie:n),n=j(e,s.innerHTML,r,i)),n.tmplName=e=e||o,e!==Ie&&(re[e]=n),s.setAttribute(Se,e),t.fn&&t.data(s,Ie,n))),s=void 0}else n.fn||(n=void 0);return n}var s,a,d=n=n||"";return 0===i&&(i=void 0,d=o(d)),i=i||(n.markup?n:{}),i.tmplName=e,r&&(i._parentTmpl=r),!d&&n.markup&&(d=o(n.markup))&&d.fn&&(d=d.markup),void 0!==d?(d.fn||n.fn?d.fn&&(a=d):(n=V(d,i),U(d.replace(ke,"\\$&"),n)),a||(_(i),a=u(function(){return n.render.apply(n,arguments)},n)),e&&!r&&e!==Ie&&(qe[e]=a),a):void 0}function C(e,n){return t.isFunction(e)?e.call(n):e}function A(e){var t,n=[],r=e.length;for(t=0;r>t;t++)n.push(e[t].unmap());return n}function T(e,n){function r(e){l.apply(this,e)}function i(){return new r(arguments)}function o(e,t){var n,r,i,o,s,a=c.length;for(n=0;a>n;n++)o=c[n],r=void 0,o+""!==o&&(r=o,o=r.getter),void 0===(s=e[o])&&r&&void 0!==(i=r.defaultVal)&&(s=C(i,e)),t(s,r&&p[r.type],o)}function s(n){n=n+""===n?JSON.parse(n):n;var r,i,s,u=n,l=[];if(t.isArray(n)){for(n=n||[],i=n.length,r=0;i>r;r++)l.push(this.map(n[r]));return l._is=e,l.unmap=d,l.merge=a,l}if(n){o(n,function(e,t){t&&(e=t.map(e)),l.push(e)}),u=this.apply(this,l);for(s in n)s===ee||b[s]||(u[s]=n[s])}return u}function a(e){e=e+""===e?JSON.parse(e):e;var n,r,s,a,d,u,l,p,c,f,v=this;if(t.isArray(v)){for(p={},f=[],s=e.length,a=v.length,n=0;s>n;n++){for(c=e[n],l=!1,r=0;a>r&&!l;r++)p[r]||(u=v[r],g&&(p[r]=l=g+""===g?c[g]&&(b[g]?u[g]():u[g])===c[g]:g(u,c)));l?(u.merge(c),f.push(u)):f.push(i.map(c))}return void(x?x(v).refresh(f,!0):v.splice.apply(v,[0,v.length].concat(f)))}o(e,function(e,t,n){t?v[n]().merge(e):v[n](e)});for(d in e)d===ee||b[d]||(v[d]=e[d])}function d(){var e,n,r,i,o,s,a=this;if(t.isArray(a))return A(a);for(e={},i=c.length,r=0;i>r;r++)n=c[r],o=void 0,n+""!==n&&(o=n,n=o.getter),s=a[n](),e[n]=o&&s&&p[o.type]?t.isArray(s)?A(s):s.unmap():s;for(n in a)"_is"===n||b[n]||n===ee||"_"===n.charAt(0)&&b[n.slice(1)]||t.isFunction(a[n])||(e[n]=a[n]);return e}var u,l,p=this,c=n.getters,f=n.extend,g=n.id,v=t.extend({_is:e||"unnamed",unmap:d,merge:a},f),h="",m="",w=c?c.length:0,x=t.observable,b={};for(r.prototype=v,u=0;w>u;u++)!function(e){e=e.getter||e,b[e]=u+1;var t="_"+e;h+=(h?",":"")+e,m+="this."+t+" = "+e+";\n",v[e]=v[e]||function(n){return arguments.length?void(x?x(this).setProperty(e,n):this[t]=n):this[t]},x&&(v[e].set=v[e].set||function(e){this[t]=e})}(c[u]);return l=new Function(h,m.slice(0,-1)),l.prototype=v,v.constructor=l,i.map=s,i.getters=c,i.extend=f,i.id=g,i}function V(e,n){var r,i=ue._wm||{},o=u({tmpls:[],links:{},bnds:[],_is:"template",render:N},n);return o.markup=e,n.htmlTag||(r=Ae.exec(e),o.htmlTag=r?r[1].toLowerCase():""),r=i[o.htmlTag],r&&r!==i.div&&(o.markup=t.trim(o.markup)),o}function R(e,t){function n(i,o,s){var a,d,u,l;if(i&&typeof i===Fe&&!i.nodeType&&!i.markup&&!i.getTgt&&!("viewModel"===e&&i.getters||i.extend)){for(u in i)n(u,i[u],o);return o||Y}return void 0===o&&(o=i,i=void 0),i&&""+i!==i&&(s=o,o=i,i=void 0),l=s?"viewModel"===e?s:s[r]=s[r]||{}:n,d=t.compile,null===o?i&&delete l[i]:(o=d?d.call(l,i,o,s,0):o,i&&(l[i]=o)),d&&o&&(o._is=e),o&&(a=ae.onStore[e])&&a(i,o,d),o}var r=e+"s";Y[r]=n}function M(e){le[e]=function(t){return arguments.length?(de[e]=t,le):de[e]}}function $(e){function t(t,n){this.tgt=e.getTgt(t,n)}return te(e)&&(e={getTgt:e}),e.baseMap&&(e=u(u({},e.baseMap),e)),e.map=function(e,n){return new t(e,n)},e}function N(e,t,n,r,i,o){var s,a,d,u,l,p,c,f,g=r,v="";if(t===!0?(n=t,t=void 0):typeof t!==Fe&&(t=void 0),(d=this.tag)?(l=this,g=g||l.view,u=g.getTmpl(d.template||l.tmpl),arguments.length||(e=g)):u=this,u){if(!g&&e&&"view"===e._is&&(g=e),g&&e===g&&(e=g.data),p=!g,me=me||p,g||((t=t||{}).root=e),!me||ue.useViews||u.useViews||g&&g!==X)v=E(u,e,t,n,g,i,o,d);else{if(g?(c=g.data,f=g.index,g.index=Ue):(g=X,g.data=e,g.ctx=t),ne(e)&&!n)for(s=0,a=e.length;a>s;s++)g.index=s,g.data=e[s],v+=u.fn(e[s],g,ae);else g.data=e,v+=u.fn(e,g,ae);g.data=c,g.index=f}p&&(me=void 0)}return v}function E(e,t,n,r,i,o,s,a){function d(e){_=u({},n),_[x]=e}var l,p,c,f,g,v,h,m,w,x,_,y,k="";if(a&&(w=a.tagName,y=a.tagCtx,n=n?L(n,a.ctx):a.ctx,e===i.content?h=e!==i.ctx._wrp?i.ctx._wrp:void 0:e!==y.content?e===a.template?(h=y.tmpl,n._wrp=y.content):h=y.content||i.content:h=i.content,y.props.link===!1&&(n=n||{},n.link=!1),(x=y.props.itemVar)&&("~"!==x.charAt(0)&&I("Use itemVar='~myItem'"),x=x.slice(1))),i&&(s=s||i._.onRender,n=L(n,i.ctx)),o===!0&&(v=!0,o=0),s&&(n&&n.link===!1||a&&a._.noVws)&&(s=void 0),m=s,s===!0&&(m=void 0,s=i._.onRender),n=e.helpers?L(e.helpers,n):n,_=n,ne(t)&&!r)for(c=v?i:void 0!==o&&i||new b(n,"array",i,t,e,o,s),i&&i._.useKey&&(c._.bnd=!a||a._.bnd&&a),x&&(c.it=x),x=c.it,l=0,p=t.length;p>l;l++)x&&d(t[l]),f=new b(_,"item",c,t[l],e,(o||0)+l,s,h),g=e.fn(t[l],f,ae),k+=c._.onRender?c._.onRender(g,f):g;else x&&d(t),c=v?i:new b(_,w||"data",i,t,e,o,s,h),a&&!a.flow&&(c.tag=a),k+=e.fn(t,c,ae);return m?m(k,c):k}function F(e,t,n){var r=void 0!==n?te(n)?n.call(t.data,e,t):n||"":"{Error: "+e.message+"}";return de.onError&&void 0!==(n=de.onError.call(t.data,e,n&&r,t))&&(r=n),t&&!t.linkCtx?ie.html(r):r}function S(e){throw new ae.Err(e)}function I(e){S("Syntax error\n"+e)}function U(e,t,n,r,i){function o(t){t-=v,t&&m.push(e.substr(v,t).replace(_e,"\\n"))}function s(t,n){t&&(t+="}}",I((n?"{{"+n+"}} block has {{/"+t+" without {{"+t:"Unmatched or missing {{/"+t)+", in template:\n"+e))}function a(a,d,u,c,g,x,b,_,y,k,j,C){(b&&d||y&&!u||_&&":"===_.slice(-1)||k)&&I(a),x&&(g=":",c=Ee),y=y||n&&!i;var A=(d||n)&&[[]],T="",V="",R="",M="",$="",N="",E="",F="",S=!y&&!g;u=u||(_=_||"#data",g),o(C),v=C+a.length,b?f&&m.push(["*","\n"+_.replace(/^:/,"ret+= ").replace(ye,"$1")+";\n"]):u?("else"===u&&(Ce.test(_)&&I('for "{{else if expr}}" use "{{else expr}}"'),A=w[7]&&[[]],w[8]=e.substring(w[8],C),w=h.pop(),m=w[2],S=!0),_&&O(_.replace(_e," "),A,t).replace(je,function(e,t,n,r,i,o,s,a){return r="'"+i+"':",s?(V+=o+",",M+="'"+a+"',"):n?(R+=r+o+",",N+=r+"'"+a+"',"):t?E+=o:("trigger"===i&&(F+=o),T+=r+o+",",$+=r+"'"+a+"',",p=p||Re.test(i)),""}).slice(0,-1),A&&A[0]&&A.pop(),l=[u,c||!!r||p||"",S&&[],J(M||(":"===u?"'#data',":""),$,N),J(V||(":"===u?"data,":""),T,R),E,F,A||0],m.push(l),S&&(h.push(w),w=l,w[8]=v)):j&&(s(j!==w[0]&&"else"!==w[0]&&j,w[0]),w[8]=e.substring(w[8],C),w=h.pop()),s(!w&&j),m=w[2]}var d,u,l,p,c,f=de.allowCode||t&&t.allowCode||le.allowCode===!0,g=[],v=0,h=[],m=g,w=[,,g];if(f&&(t.allowCode=f),n&&(void 0!==r&&(e=e.slice(0,-r.length-2)+ge),e=pe+e+ge),s(h[0]&&h[0][2].pop()[0]),e.replace(G,a),o(e.length),(v=g[g.length-1])&&s(""+v!==v&&+v[8]===v[8]&&v[0]),n){for(u=B(g,e,n),c=[],d=g.length;d--;)c.unshift(g[d][7]);q(u,c)}else u=B(g,t);return u}function q(e,t){var n,r,i=0,o=t.length;for(e.deps=[];o>i;i++){r=t[i];for(n in r)"_jsvto"!==n&&r[n].length&&(e.deps=e.deps.concat(r[n]))}e.paths=r}function J(e,t,n){return[e.slice(0,-1),t.slice(0,-1),n.slice(0,-1)]}function K(e,t){return"\n "+(t?t+":{":"")+"args:["+e[0]+"]"+(e[1]||!t?",\n props:{"+e[1]+"}":"")+(e[2]?",\n ctx:{"+e[2]+"}":"")}function O(e,t,n){function r(r,m,w,x,b,_,y,k,j,C,A,T,V,R,M,$,N,E,F,S){function q(e,n,r,s,a,d,p,c){var f="."===r;if(r&&(b=b.slice(n.length),/^\.?constructor$/.test(c||b)&&I(e),f||(e=(s?'view.hlp("'+s+'")':a?"view":"data")+(c?(d?"."+d:s?"":a?"":"."+r)+(p||""):(c=s?"":a?d||"":r,"")),e+=c?"."+c:"",e=n+("view.data"===e.slice(0,9)?e.slice(5):e)),u)){if(O="linkTo"===i?o=t._jsvto=t._jsvto||[]:l.bd,B=f&&O[O.length-1]){if(B._jsv){for(;B.sb;)B=B.sb;B.bnd&&(b="^"+b.slice(1)),B.sb=b,B.bnd=B.bnd||"^"===b.charAt(0)}}else O.push(b);h[g]=F+(f?1:0)}return e}x=u&&x,x&&!k&&(b=x+b),_=_||"",w=w||m||T,b=b||j,C=C||N||"";var J,K,O,B,L,Q=")";if("["===C&&(C="[j._sq(",Q=")]"),!y||d||a){if(u&&$&&!d&&!a&&(!i||s||o)&&(J=h[g-1],S.length-1>F-(J||0))){if(J=S.slice(J,F+r.length),K!==!0)if(O=o||p[g-1].bd,B=O[O.length-1],B&&B.prm){for(;B.sb&&B.sb.prm;)B=B.sb;L=B.sb={path:B.sb,bnd:B.bnd}}else O.push(L={path:O.pop()});$=ce+":"+J+" onerror=''"+fe,K=f[$],K||(f[$]=!0,f[$]=K=U($,n,!0)),K!==!0&&L&&(L._jsv=K,L.prm=l.bd,L.bnd=L.bnd||L.path&&L.path.indexOf("^")>=0)}return d?(d=!V,d?r:T+'"'):a?(a=!R,a?r:T+'"'):(w?(h[g]=F++,l=p[++g]={bd:[]},w):"")+(E?g?"":(c=S.slice(c,F),(i?(i=s=o=!1,"\b"):"\b,")+c+(c=F+r.length,u&&t.push(l.bd=[]),"\b")):k?(g&&I(e),u&&t.pop(),i=b,s=x,c=F+r.length,x&&(u=l.bd=t[i]=[]),b+":"):b?b.split("^").join(".").replace(xe,q)+(C?(l=p[++g]={bd:[]},v[g]=Q,C):_):_?_:M?(M=v[g]||M,v[g]=!1,l=p[--g],M+(C?(l=p[++g],v[g]=Q,C):"")):A?(v[g]||I(e),","):m?"":(d=V,a=R,'"'))}I(e)}var i,o,s,a,d,u=t&&t[0],l={bd:u},p={0:l},c=0,f=n?n.links:u&&(u.links=u.links||{}),g=0,v={},h={},m=(e+(n?" ":"")).replace(be,r);return!g&&m||I(e)}function B(e,t,n){var r,i,o,s,a,d,u,l,p,c,f,g,v,h,m,w,x,b,_,y,k,j,C,A,T,R,M,$,N,E,F=0,S=ue.useViews||t.useViews||t.tags||t.templates||t.helpers||t.converters,U="",J={},O=e.length;for(""+t===t?(b=n?'data-link="'+t.replace(_e," ").slice(1,-1)+'"':t,t=0):(b=t.tmplName||"unnamed",t.allowCode&&(J.allowCode=!0),t.debug&&(J.debug=!0),f=t.bnds,x=t.tmpls),r=0;O>r;r++)if(i=e[r],""+i===i)U+='\n+"'+i+'"';else if(o=i[0],"*"===o)U+=";\n"+i[1]+"\nret=ret";else{if(s=i[1],k=!n&&i[2],a=K(i[3],"params")+"},"+K(v=i[4]),$=i[5],E=i[6],j=i[8]&&i[8].replace(ye,"$1"),(T="else"===o)?g&&g.push(i[7]):(F=0,f&&(g=i[7])&&(g=[g],F=f.push(1))),S=S||v[1]||v[2]||g||/view.(?!index)/.test(v[0]),(R=":"===o)?s&&(o=s===Ee?">":s+o):(k&&(_=V(j,J),_.tmplName=b+"/"+o,_.useViews=_.useViews||S,B(k,_),S=_.useViews,x.push(_)),T||(y=o,S=S||o&&(!se[o]||!se[o].flow),A=U,U=""),C=e[r+1],C=C&&"else"===C[0]),N=$?";\ntry{\nret+=":"\n+",h="",m="",R&&(g||E||s&&s!==Ee)){if(M=new Function("data,view,j,u"," // "+b+" "+F+" "+o+"\nreturn {"+a+"};"),M._er=$,M._tag=o,n)return M;q(M,g),w='c("'+s+'",view,',c=!0,h=w+F+",",m=")"}if(U+=R?(n?($?"try{\n":"")+"return ":N)+(c?(c=void 0,S=p=!0,w+(g?(f[F-1]=M,F):"{"+a+"}")+")"):">"===o?(u=!0,"h("+v[0]+")"):(l=!0,"((v="+v[0]+")!=null?v:"+(n?"null)":'"")'))):(d=!0,"\n{view:view,tmpl:"+(k?x.length:"0")+","+a+"},"),y&&!C){if(U="["+U.slice(0,-1)+"]",w='t("'+y+'",view,this,',n||g){if(U=new Function("data,view,j,u"," // "+b+" "+F+" "+y+"\nreturn "+U+";"),U._er=$,U._tag=y,g&&q(f[F-1]=U,g),n)return U;h=w+F+",undefined,",m=")"}U=A+N+w+(F||U)+")",g=0,y=0}$&&(S=!0,U+=";\n}catch(e){ret"+(n?"urn ":"+=")+h+"j._err(e,view,"+$+")"+m+";}"+(n?"":"ret=ret"))}U="// "+b+"\nvar v"+(d?",t=j._tag":"")+(p?",c=j._cnvt":"")+(u?",h=j._html":"")+(n?";\n":',ret=""\n')+(J.debug?"debugger;":"")+U+(n?"\n":";\nreturn ret;"),de.debugMode!==!1&&(U="try {\n"+U+"\n}catch(e){\nreturn j._err(e, view);\n}");try{U=new Function("data,view,j,u",U)}catch(L){I("Compiled template code:\n\n"+U+'\n: "'+L.message+'"')}return t&&(t.fn=U,t.useViews=!!S),U}function L(e,t){return e&&e!==t?t?u(u({},t),e):e:t&&u({},t)}function Q(e){return Ne[e]||(Ne[e]="&#"+e.charCodeAt(0)+";")}function H(e){var t,n,r=[];if(typeof e===Fe)for(t in e)n=e[t],t===ee||te(n)||r.push({key:t,prop:n});return r}function P(e,n,r){var i=this.jquery&&(this[0]||S('Unknown template: "'+this.selector+'"')),o=i.getAttribute(Se);return N.call(o?t.data(i)[Ie]:re(i),e,n,r)}function D(e){return void 0!=e?Ve.test(e)&&(""+e).replace(Me,Q)||e:""}var Z=t===!1;t=t&&t.fn?t:e.jQuery;var z,G,W,X,Y,ee,te,ne,re,ie,oe,se,ae,de,ue,le,pe,ce,fe,ge,ve,he,me,we="v0.9.78",xe=/^(!*?)(?:null|true|false|\d[\d.]*|([\w$]+|\.|~([\w$]+)|#(view|([\w$]+))?)([\w$.^]*?)(?:[.[^]([\w$]+)\]?)?)$/g,be=/(\()(?=\s*\()|(?:([([])\s*)?(?:(\^?)(!*?[#~]?[\w$.^]+)?\s*((\+\+|--)|\+|-|&&|\|\||===|!==|==|!=|<=|>=|[<>%*:?\/]|(=))\s*|(!*?[#~]?[\w$.^]+)([([])?)|(,\s*)|(\(?)\\?(?:(')|("))|(?:\s*(([)\]])(?=\s*[.^]|\s*$|[^([])|[)\]])([([]?))|(\s+)/g,_e=/[ \t]*(\r\n|\n|\r)/g,ye=/\\(['"])/g,ke=/['"\\]/g,je=/(?:\x08|^)(onerror:)?(?:(~?)(([\w$_\.]+):)?([^\x08]+))\x08(,)?([^\x08]+)/gi,Ce=/^if\s/,Ae=/<(\w+)[>\s]/,Te=/[\x00`><"'&=]/g,Ve=/[\x00`><\"'&=]/,Re=/^on[A-Z]|^convert(Back)?$/,Me=Te,$e=0,Ne={"&":"&","<":"<",">":">","\x00":"�","'":"'",'"':""","`":"`","=":"="},Ee="html",Fe="object",Se="data-jsv-tmpl",Ie="jsvTmpl",Ue="For #index in nested block use #getIndex().",qe={},Je=e.jsrender,Ke=Je&&t&&!t.render,Oe={template:{compile:j},tag:{compile:y},viewModel:{compile:T},helper:{},converter:{}};if(Y={jsviews:we,sub:{View:b,Err:d,tmplFn:U,parse:O,extend:u,extendCtx:L,syntaxErr:I,onStore:{},addSetting:M,settings:{allowCode:!1},advSet:s,_ths:i,_tg:function(){},_cnvt:h,_tag:x,_er:S,_err:F,_html:D,_sq:function(e){return"constructor"===e&&I(""),e}},settings:{delimiters:l,advanced:function(e){return e?(u(ue,e),ae.advSet(),le):ue}},map:$},(d.prototype=new Error).constructor=d,c.depends=function(){return[this.get("item"),"index"]},f.depends="index",b.prototype={get:p,getIndex:f,getRsc:w,getTmpl:v,hlp:g,_is:"view"},ae=Y.sub,le=Y.settings,!(Je||t&&t.render)){for(z in Oe)R(z,Oe[z]);ie=Y.converters,oe=Y.helpers,se=Y.tags,ae._tg.prototype={baseApply:k,cvtArgs:m},X=ae.topView=new b,t?(t.fn.render=P,ee=t.expando,t.observable&&(u(ae,t.views.sub),Y.map=t.views.map)):(t={},Z&&(e.jsrender=t),t.renderFile=t.__express=t.compile=function(){throw"Node.js: use npm jsrender, or jsrender-node.js"},t.isFunction=function(e){return"function"==typeof e},t.isArray=Array.isArray||function(e){return"[object Array]"==={}.toString.call(e)},ae._jq=function(e){e!==t&&(u(e,t),t=e,t.fn.render=P,delete t.jsrender,ee=t.expando)},t.jsrender=we),de=ae.settings,de.allowCode=!1,te=t.isFunction,ne=t.isArray,t.render=qe,t.views=Y,t.templates=re=Y.templates;for(he in de)M(he);(le.debugMode=function(e){return void 0===e?de.debugMode:(de.debugMode=e,de.onError=e+""===e?new Function("","return '"+e+"';"):te(e)?e:void 0,le)})(!1),ue=de.advanced={useViews:!1,_jsv:!1},se({"if":{render:function(e){var t=this,n=t.tagCtx,r=t.rendering.done||!e&&(arguments.length||!n.index)?"":(t.rendering.done=!0,t.selected=n.index,n.render(n.view,!0));return r},flow:!0},"for":{render:function(e){var t,n=!arguments.length,r=this,i=r.tagCtx,o="",s=0;return r.rendering.done||(t=n?i.view.data:e,void 0!==t&&(o+=i.render(t,n),s+=ne(t)?t.length:1),(r.rendering.done=s)&&(r.selected=i.index)),o},flow:!0},props:{baseTag:"for",dataMap:$(H),flow:!0},include:{flow:!0},"*":{render:o,flow:!0},":*":{render:o,flow:!0},dbg:oe.dbg=ie.dbg=a}),ie({html:D,attr:D,url:function(e){return void 0!=e?encodeURI(""+e):null===e?e:""}})}return de=ae.settings,le.delimiters("{{","}}","^"),Ke&&Je.views.sub._jq(t),t||Je},window); | ||
4 | //# sourceMappingURL=jsrender.min.js.map | ||
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js index eafe70ddee..a61b10e972 100644 --- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js +++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js | |||
@@ -148,6 +148,21 @@ var libtoaster = (function () { | |||
148 | }); | 148 | }); |
149 | } | 149 | } |
150 | 150 | ||
151 | function _getMostRecentBuilds(url, onsuccess, onfail) { | ||
152 | $.ajax({ | ||
153 | url: url, | ||
154 | type: 'GET', | ||
155 | data : {format: 'json'}, | ||
156 | headers: {'X-CSRFToken': $.cookie('csrftoken')}, | ||
157 | success: function (data) { | ||
158 | onsuccess ? onsuccess(data) : console.log(data); | ||
159 | }, | ||
160 | error: function (data) { | ||
161 | onfail ? onfail(data) : console.error(data); | ||
162 | } | ||
163 | }); | ||
164 | } | ||
165 | |||
151 | /* Get a project's configuration info */ | 166 | /* Get a project's configuration info */ |
152 | function _getProjectInfo(url, onsuccess, onfail){ | 167 | function _getProjectInfo(url, onsuccess, onfail){ |
153 | $.ajax({ | 168 | $.ajax({ |
@@ -426,6 +441,7 @@ var libtoaster = (function () { | |||
426 | reload_params : reload_params, | 441 | reload_params : reload_params, |
427 | startABuild : _startABuild, | 442 | startABuild : _startABuild, |
428 | cancelABuild : _cancelABuild, | 443 | cancelABuild : _cancelABuild, |
444 | getMostRecentBuilds: _getMostRecentBuilds, | ||
429 | makeTypeahead : _makeTypeahead, | 445 | makeTypeahead : _makeTypeahead, |
430 | getProjectInfo: _getProjectInfo, | 446 | getProjectInfo: _getProjectInfo, |
431 | getLayerDepsForProject : _getLayerDepsForProject, | 447 | getLayerDepsForProject : _getLayerDepsForProject, |
diff --git a/bitbake/lib/toaster/toastergui/static/js/mrbsection.js b/bitbake/lib/toaster/toastergui/static/js/mrbsection.js index 9a76ee6407..d8c3bf7750 100644 --- a/bitbake/lib/toaster/toastergui/static/js/mrbsection.js +++ b/bitbake/lib/toaster/toastergui/static/js/mrbsection.js | |||
@@ -1,33 +1,19 @@ | |||
1 | 1 | ||
2 | function mrbSectionInit(ctx){ | 2 | function mrbSectionInit(ctx){ |
3 | 3 | $('#latest-builds').on('click', '.cancel-build-btn', function(e){ | |
4 | var projectBuilds; | 4 | e.stopImmediatePropagation(); |
5 | |||
6 | if (ctx.mrbType === 'project') | ||
7 | projectBuilds = true; | ||
8 | |||
9 | $(".cancel-build-btn").click(function(e){ | ||
10 | e.preventDefault(); | 5 | e.preventDefault(); |
11 | 6 | ||
12 | var url = $(this).data('request-url'); | 7 | var url = $(this).data('request-url'); |
13 | var buildReqIds = $(this).data('buildrequest-id'); | 8 | var buildReqIds = $(this).data('buildrequest-id'); |
14 | var banner = $(this).parents(".alert"); | 9 | |
15 | 10 | libtoaster.cancelABuild(url, buildReqIds, function () { | |
16 | banner.find(".progress-info").fadeOut().promise().done(function(){ | 11 | window.location.reload(); |
17 | $("#cancelling-msg-" + buildReqIds).show(); | 12 | }, null); |
18 | console.log("cancel build"); | ||
19 | libtoaster.cancelABuild(url, buildReqIds, function(){ | ||
20 | if (projectBuilds == false){ | ||
21 | /* the all builds page is not 'self updating' like thei | ||
22 | * project Builds | ||
23 | */ | ||
24 | window.location.reload(); | ||
25 | } | ||
26 | }, null); | ||
27 | }); | ||
28 | }); | 13 | }); |
29 | 14 | ||
30 | $(".run-again-btn").click(function(e){ | 15 | $('#latest-builds').on('click', '.rebuild-btn', function(e){ |
16 | e.stopImmediatePropagation(); | ||
31 | e.preventDefault(); | 17 | e.preventDefault(); |
32 | 18 | ||
33 | var url = $(this).data('request-url'); | 19 | var url = $(this).data('request-url'); |
@@ -38,58 +24,110 @@ function mrbSectionInit(ctx){ | |||
38 | }, null); | 24 | }, null); |
39 | }); | 25 | }); |
40 | 26 | ||
27 | // cached version of buildData, so we can determine whether a build has | ||
28 | // changed since it was last fetched, and update the DOM appropriately | ||
29 | var buildData = {}; | ||
41 | 30 | ||
42 | var progressTimer; | 31 | // returns the cached version of this build, or {} is there isn't a cached one |
43 | 32 | function getCached(build) { | |
44 | if (projectBuilds === true){ | 33 | return buildData[build.id] || {}; |
45 | progressTimer = window.setInterval(function() { | 34 | } |
46 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, | 35 | |
47 | function(prjInfo){ | 36 | // returns true if a build's state changed to "Succeeded" or "Failed" |
48 | /* These two are needed because a build can be 100% and still | 37 | // from some other value |
49 | * in progress due to the fact that the % done is updated at the | 38 | function buildFinished(build) { |
50 | * start of a task so it can be doing the last task at 100% | 39 | var cached = getCached(build); |
51 | */ | 40 | return cached.state && |
52 | var inProgress = 0; | 41 | cached.state !== build.state && |
53 | var allPercentDone = 0; | 42 | (build.state == 'Succeeded' || build.state == 'Failed' || |
54 | if (prjInfo.builds.length === 0) | 43 | build.state == 'Cancelled'); |
55 | return | 44 | } |
56 | |||
57 | for (var i in prjInfo.builds){ | ||
58 | var build = prjInfo.builds[i]; | ||
59 | |||
60 | if (build.outcomeText === "In Progress" || | ||
61 | $(".progress .bar").length > 0){ | ||
62 | /* Update the build progress */ | ||
63 | var percentDone; | ||
64 | |||
65 | if (build.outcomeText !== "In Progress"){ | ||
66 | /* We have to ignore the value when it's Succeeded because it | ||
67 | * goes back to 0 | ||
68 | */ | ||
69 | percentDone = 100; | ||
70 | } else { | ||
71 | percentDone = build.percentDone; | ||
72 | inProgress++; | ||
73 | } | ||
74 | |||
75 | $("#build-pc-done-" + build.id).text(percentDone); | ||
76 | $("#build-pc-done-title-" + build.id).attr("title", percentDone); | ||
77 | $("#build-pc-done-bar-" + build.id).css("width", | ||
78 | String(percentDone) + "%"); | ||
79 | |||
80 | allPercentDone += percentDone; | ||
81 | } | ||
82 | } | ||
83 | 45 | ||
84 | if (allPercentDone === (100 * prjInfo.builds.length) && !inProgress) | 46 | // returns true if the state changed |
47 | function stateChanged(build) { | ||
48 | var cached = getCached(build); | ||
49 | return (cached.state !== build.state); | ||
50 | } | ||
51 | |||
52 | // returns true if the complete_percentage changed | ||
53 | function progressChanged(build) { | ||
54 | var cached = getCached(build); | ||
55 | return (cached.tasks_complete_percentage !== build.tasks_complete_percentage); | ||
56 | } | ||
57 | |||
58 | function refreshMostRecentBuilds(){ | ||
59 | libtoaster.getMostRecentBuilds( | ||
60 | libtoaster.ctx.mostRecentBuildsUrl, | ||
61 | |||
62 | // success callback | ||
63 | function (data) { | ||
64 | var build; | ||
65 | var tmpl; | ||
66 | var container; | ||
67 | var selector; | ||
68 | var colourClass; | ||
69 | var elements; | ||
70 | |||
71 | // classes on the parent which signify the build state and affect | ||
72 | // the colour of the container for the build | ||
73 | var buildStateClasses = 'alert-info alert-success alert-danger'; | ||
74 | |||
75 | for (var i = 0; i < data.length; i++) { | ||
76 | build = data[i]; | ||
77 | |||
78 | if (buildFinished(build)) { | ||
79 | // a build finished: reload the whole page so that the build | ||
80 | // shows up in the builds table | ||
85 | window.location.reload(); | 81 | window.location.reload(); |
82 | } | ||
83 | else if (stateChanged(build)) { | ||
84 | // update the whole template | ||
85 | tmpl = $.templates("#build-template"); | ||
86 | |||
87 | html = tmpl.render(build); | ||
88 | |||
89 | selector = '[data-latest-build-result="' + build.id + '"] ' + | ||
90 | '[data-role="build-status-container"]'; | ||
91 | container = $(selector); | ||
92 | |||
93 | container.html(html); | ||
94 | |||
95 | // style the outermost container for this build to reflect | ||
96 | // the new build state (red, green, blue); | ||
97 | // NB class set here should be in buildStateClasses | ||
98 | colourClass = 'alert-info'; | ||
99 | if (build.state == 'Succeeded') { | ||
100 | colourClass = 'alert-success'; | ||
101 | } | ||
102 | else if (build.state == 'Failed') { | ||
103 | colourClass = 'alert-danger'; | ||
104 | } | ||
86 | 105 | ||
87 | /* Our progress bar is not still showing so shutdown the polling. */ | 106 | elements = $('[data-latest-build-result="' + build.id + '"]'); |
88 | if ($(".progress .bar").length === 0) | 107 | elements.removeClass(buildStateClasses); |
89 | window.clearInterval(progressTimer); | 108 | elements.addClass(colourClass); |
109 | } | ||
110 | else if (progressChanged(build)) { | ||
111 | // update the progress text | ||
112 | selector = '#build-pc-done-' + build.id; | ||
113 | $(selector).html(build.tasks_complete_percentage); | ||
114 | |||
115 | // update the progress bar | ||
116 | selector = '#build-pc-done-bar-' + build.id; | ||
117 | $(selector).width(build.tasks_complete_percentage + '%'); | ||
118 | } | ||
90 | 119 | ||
91 | }); | 120 | buildData[build.id] = build; |
92 | }, 1500); | 121 | } |
122 | }, | ||
123 | |||
124 | // fail callback | ||
125 | function (data) { | ||
126 | console.error(data); | ||
127 | } | ||
128 | ); | ||
93 | } | 129 | } |
94 | } | ||
95 | 130 | ||
131 | window.setInterval(refreshMostRecentBuilds, 1000); | ||
132 | refreshMostRecentBuilds(); | ||
133 | } | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html index 8a9f690309..58491eba81 100644 --- a/bitbake/lib/toaster/toastergui/templates/base.html +++ b/bitbake/lib/toaster/toastergui/templates/base.html | |||
@@ -22,6 +22,8 @@ | |||
22 | </script> | 22 | </script> |
23 | <script src="{% static 'js/typeahead.jquery.js' %}"> | 23 | <script src="{% static 'js/typeahead.jquery.js' %}"> |
24 | </script> | 24 | </script> |
25 | <script src="{% static 'js/jsrender.min.js' %}"> | ||
26 | </script> | ||
25 | <script src="{% static 'js/prettify.js' %}"> | 27 | <script src="{% static 'js/prettify.js' %}"> |
26 | </script> | 28 | </script> |
27 | <script src="{% static 'js/libtoaster.js' %}"> | 29 | <script src="{% static 'js/libtoaster.js' %}"> |
@@ -32,6 +34,8 @@ | |||
32 | </script> | 34 | </script> |
33 | {% endif %} | 35 | {% endif %} |
34 | <script> | 36 | <script> |
37 | $.views.settings.delimiters("<%", "%>"); | ||
38 | |||
35 | libtoaster.ctx = { | 39 | libtoaster.ctx = { |
36 | jsUrl : "{% static 'js/' %}", | 40 | jsUrl : "{% static 'js/' %}", |
37 | htmlUrl : "{% static 'html/' %}", | 41 | htmlUrl : "{% static 'html/' %}", |
@@ -48,7 +52,9 @@ | |||
48 | xhrCustomRecipeUrl : "{% url 'xhr_customrecipe' %}", | 52 | xhrCustomRecipeUrl : "{% url 'xhr_customrecipe' %}", |
49 | projectId : {{project.id}}, | 53 | projectId : {{project.id}}, |
50 | xhrBuildRequestUrl: "{% url 'xhr_buildrequest' project.id %}", | 54 | xhrBuildRequestUrl: "{% url 'xhr_buildrequest' project.id %}", |
55 | mostRecentBuildsUrl: "{% url 'most_recent_builds' %}?project_id={{project.id}}", | ||
51 | {% else %} | 56 | {% else %} |
57 | mostRecentBuildsUrl: "{% url 'most_recent_builds' %}", | ||
52 | projectId : undefined, | 58 | projectId : undefined, |
53 | projectPageUrl : undefined, | 59 | projectPageUrl : undefined, |
54 | projectName : undefined, | 60 | projectName : undefined, |
diff --git a/bitbake/lib/toaster/toastergui/templates/buildrequestdetails.html b/bitbake/lib/toaster/toastergui/templates/buildrequestdetails.html deleted file mode 100644 index c782074448..0000000000 --- a/bitbake/lib/toaster/toastergui/templates/buildrequestdetails.html +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | {% extends "baseprojectpage.html" %} | ||
2 | |||
3 | {% load static %} | ||
4 | {% load projecttags %} | ||
5 | {% load humanize %} | ||
6 | |||
7 | |||
8 | {% block projectinfomain %} | ||
9 | <!-- begin content --> | ||
10 | |||
11 | <div class="row"> | ||
12 | |||
13 | <!-- end left sidebar container --> | ||
14 | <!-- Begin right container --> | ||
15 | <div class="col-md-10"> | ||
16 | <div class="page-header"> | ||
17 | <h1> | ||
18 | <span data-toggle="tooltip" {%if buildrequest.brtarget_set.all.count > 1%}title="Targets: {%for target in buildrequest.brtarget_set.all%}{{target.target}} {%endfor%}"{%endif%}>{{buildrequest.brtarget_set.all.0.target}} {%if buildrequest.brtarget_set.all.count > 1%}(+ {{buildrequest.brtarget_set.all.count|add:"-1"}}){%endif%} {{buildrequest.get_machine}} </span> | ||
19 | |||
20 | </h1> | ||
21 | </div> | ||
22 | <div class="alert alert-error"> | ||
23 | <p class="lead"> | ||
24 | <strong>Failed</strong> | ||
25 | on {{ buildrequest.updated|date:'d/m/y H:i' }} | ||
26 | with | ||
27 | |||
28 | <i class="icon-minus-sign error" style="margin-left:6px;"></i> | ||
29 | <strong><a class="error accordion-toggle toggle-errors" href="#errors"> | ||
30 | {{buildrequest.brerror_set.all.count}} error{{buildrequest.brerror_set.all.count|pluralize}} | ||
31 | </a></strong> | ||
32 | <span class="pull-right">Build time: {{buildrequest.get_duration|sectohms}}</span> | ||
33 | </p> | ||
34 | </div> | ||
35 | |||
36 | <div class="accordion" id="errors"> | ||
37 | <div class="accordion-group"> | ||
38 | <div class="accordion-heading"> | ||
39 | <a class="accordion-toggle error toggle-errors"> | ||
40 | <h2> | ||
41 | <i class="icon-minus-sign"></i> | ||
42 | {{buildrequest.brerror_set.all.count}} error{{buildrequest.brerror_set.all.count|pluralize}} | ||
43 | </h2> | ||
44 | </a> | ||
45 | </div> | ||
46 | <div class="accordion-body collapse in" id="collapse-errors"> | ||
47 | <div class="accordion-inner"> | ||
48 | <div class="col-md-10"> | ||
49 | {% for error in buildrequest.brerror_set.all %} | ||
50 | <div class="alert alert-error"> | ||
51 | ERROR: <div class="air well"><pre>{{error.errmsg}}</pre></div> | ||
52 | </div> | ||
53 | {% endfor %} | ||
54 | </div> | ||
55 | </div> | ||
56 | </div> | ||
57 | |||
58 | </div> | ||
59 | </div> | ||
60 | </div> | ||
61 | </div> <!-- end of row --> | ||
62 | |||
63 | |||
64 | {%endblock%} | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/bitbake/lib/toaster/toastergui/templates/mrb_section.html index b164269a13..302b4b0da4 100644 --- a/bitbake/lib/toaster/toastergui/templates/mrb_section.html +++ b/bitbake/lib/toaster/toastergui/templates/mrb_section.html | |||
@@ -1,26 +1,9 @@ | |||
1 | {% load static %} | 1 | {% load static %} |
2 | {% load projecttags %} | ||
3 | {% load project_url_tag %} | ||
4 | {% load humanize %} | 2 | {% load humanize %} |
3 | {% load project_url_tag %} | ||
5 | <script src="{% static 'js/mrbsection.js' %}"></script> | 4 | <script src="{% static 'js/mrbsection.js' %}"></script> |
6 | 5 | ||
7 | <script> | ||
8 | $(document).ready(function () { | ||
9 | var ctx = { | ||
10 | mrbType : "{{mrb_type}}", | ||
11 | } | ||
12 | |||
13 | try { | ||
14 | mrbSectionInit(ctx); | ||
15 | } catch (e) { | ||
16 | document.write("Sorry, An error has occurred loading this page"); | ||
17 | console.warn(e); | ||
18 | } | ||
19 | }); | ||
20 | </script> | ||
21 | |||
22 | {% if mru %} | 6 | {% if mru %} |
23 | |||
24 | {% if mrb_type == 'project' %} | 7 | {% if mrb_type == 'project' %} |
25 | <h2> | 8 | <h2> |
26 | Latest project builds | 9 | Latest project builds |
@@ -38,6 +21,7 @@ | |||
38 | <div id="latest-builds"> | 21 | <div id="latest-builds"> |
39 | {% for build in mru %} | 22 | {% for build in mru %} |
40 | <div data-latest-build-result="{{build.id}}" class="alert build-result {% if build.outcome == build.SUCCEEDED %}alert-success{% elif build.outcome == build.FAILED %}alert-danger{% else %}alert-info{% endif %}"> | 23 | <div data-latest-build-result="{{build.id}}" class="alert build-result {% if build.outcome == build.SUCCEEDED %}alert-success{% elif build.outcome == build.FAILED %}alert-danger{% else %}alert-info{% endif %}"> |
24 | <!-- project title --> | ||
41 | {% if mrb_type != 'project' %} | 25 | {% if mrb_type != 'project' %} |
42 | <div class="row project-name"> | 26 | <div class="row project-name"> |
43 | <div class="col-md-12"> | 27 | <div class="col-md-12"> |
@@ -48,134 +32,180 @@ | |||
48 | </div> | 32 | </div> |
49 | {% endif %} | 33 | {% endif %} |
50 | 34 | ||
51 | <div class="row"> | 35 | <div class="row" data-role="build-status-container"> |
52 | <div class="col-md-3"> | 36 | <div class="col-md-12"> |
53 | {% if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | 37 | Loading... |
54 | <a href="{% url 'builddashboard' build.pk %}" class="alert-link"> | ||
55 | {% endif %} | ||
56 | |||
57 | {% if build.target_set.all.count > 0 %} | ||
58 | <span data-toggle="tooltip" | ||
59 | {% if build.target_set.all.count > 1 %} | ||
60 | {{build.get_sorted_target_list.0.target}} | ||
61 | title="Recipes: | ||
62 | {% for target in build.get_sorted_target_list %} | ||
63 | {% if target.task %} | ||
64 | {{target.target}}:{{target.task}} | ||
65 | {% else %} | ||
66 | {{target.target}} | ||
67 | {% endif %} | ||
68 | {% endfor %}" | ||
69 | {% endif %} | ||
70 | > | ||
71 | {% if build.target_set.all.0.task %} | ||
72 | {{build.get_sorted_target_list.0.target}}:{{build.target_set.all.0.task}} | ||
73 | {% else %} | ||
74 | {{build.get_sorted_target_list.0.target}} | ||
75 | {% endif %} | ||
76 | |||
77 | {% if build.target_set.all.count > 1 %} | ||
78 | (+{{build.target_set.all.count|add:"-1"}}) | ||
79 | {% endif %} | ||
80 | </span> | ||
81 | {% endif %} | ||
82 | {% if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
83 | </a> | ||
84 | {% endif %} | ||
85 | </div> | 38 | </div> |
39 | </div> | ||
40 | </div> | ||
41 | {% endfor %} | ||
42 | </div> | ||
43 | {% endif %} | ||
44 | |||
45 | <!-- build main template --> | ||
46 | <script id="build-template" type="text/x-jsrender"> | ||
47 | <div class="col-md-3"> | ||
48 | <!-- only show link for completed builds --> | ||
49 | <%if state == 'Succeeded' || state == 'Failed'%> | ||
50 | <a class="alert-link" href="<%:dashboard_url%>"> | ||
51 | <span data-toggle="tooltip" data-role="targets-text" title="Recipes: <%:targets%>"> | ||
52 | <%:targets_abbreviated%> | ||
53 | </span> | ||
54 | </a> | ||
55 | <%else%> | ||
56 | <span data-toggle="tooltip" data-role="targets-text" title="Recipes: <%:targets%>"> | ||
57 | <%:targets_abbreviated%> | ||
58 | </span> | ||
59 | <%/if%> | ||
60 | </div> | ||
86 | 61 | ||
87 | {% if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | 62 | <%if state == 'Queued'%> |
88 | <div class="col-md-2"> | 63 | <%include tmpl='#queued-build-template'/%> |
89 | {% if build.completed_on|format_build_date %} | 64 | <%else state == 'Succeeded' || state == 'Failed'%> |
90 | {{build.completed_on|date:'d/m/y H:i'}} | 65 | <%include tmpl='#succeeded-or-failed-build-template'/%> |
91 | {% else %} | 66 | <%else state == 'Cancelling'%> |
92 | {{ build.completed_on|date:'H:i' }} | 67 | <%include tmpl='#cancelling-build-template'/%> |
93 | {% endif %} | 68 | <%else state == 'In Progress'%> |
94 | </div> | 69 | <%include tmpl='#in-progress-build-template'/%> |
95 | {% endif %} | 70 | <%else state == 'Cancelled'%> |
96 | 71 | <%include tmpl='#cancelled-build-template'/%> | |
97 | {% if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | 72 | <%/if%> |
98 | <div class="col-md-2"> | 73 | </script> |
99 | {% if build.errors.count %} | ||
100 | <span class="glyphicon glyphicon-minus-sign"></span> | ||
101 | <a href="{%url 'builddashboard' build.pk%}#errors" class="alert-link"> | ||
102 | {{build.errors.count}} error{{build.errors.count|pluralize}} | ||
103 | </a> | ||
104 | {% endif %} | ||
105 | </div> | ||
106 | 74 | ||
107 | <div class="col-md-2"> | 75 | <!-- queued build --> |
108 | {% if build.warnings.count %} | 76 | <script id="queued-build-template" type="text/x-jsrender"> |
109 | <span class="glyphicon glyphicon-warning-sign build-warnings"></span> | 77 | <div class="col-md-5"> |
110 | <a href="{%url 'builddashboard' build.pk%}#warnings" class="alert-link build-warnings"> | 78 | Build queued |
111 | {{build.warnings.count}} warning{{build.warnings.count|pluralize}} | 79 | </div> |
112 | </a> | ||
113 | {% endif %} | ||
114 | </div> | ||
115 | 80 | ||
116 | <div class="col-md-3"> | 81 | <div class="col-md-4"> |
117 | Build time: <a class="alert-link" href="{% url 'buildtime' build.pk %}">{{ build.timespent_seconds|sectohms }} | 82 | <%if is_default_project_build%> |
118 | </a> | 83 | <!-- no cancel icon --> |
119 | 84 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue pull-right" title="Builds in this project cannot be cancelled from Toaster: they can only be cancelled from the command line"></span> | |
120 | {% if build.project.is_default %} | 85 | <%else%> |
121 | <span class="pull-right glyphicon glyphicon-question-sign get-help {% if build.outcome == build.SUCCEEDED %}get-help-green{% elif build.outcome == build.FAILED %}get-help-red{% else %}get-help-blue{% endif %}" | 86 | <!-- cancel button --> |
122 | title="Builds in this project cannot be started from Toaster: they are started from the command line"> | 87 | <span class="cancel-build-btn pull-right alert-link" |
123 | </span> | 88 | data-buildrequest-id="<%:id%>" data-request-url="<%:cancel_url%>"> |
124 | {% else %} | 89 | <span class="glyphicon glyphicon-remove-circle"></span> |
125 | <a href="#" class="run-again-btn alert-link {% if build.outcome == build.SUCCEEDED %}success{% elif build.outcome == build.FAILED %}danger{% else %}info{% endif %} pull-right" | 90 | Cancel |
126 | data-request-url="{% url 'xhr_buildrequest' build.project.pk %}" | 91 | </span> |
127 | data-target='{{build.target_set.all|get_tasks|json}}'> | 92 | <%/if%> |
128 | <span class="glyphicon glyphicon-repeat"></span> | 93 | </div> |
129 | Rebuild | 94 | </script> |
130 | </a> | ||
131 | {% endif %} | ||
132 | </div> | ||
133 | {% endif %} | ||
134 | 95 | ||
135 | {% if build.outcome == build.IN_PROGRESS %} | 96 | <!-- in progress build --> |
136 | <div class="col-md-4" style="display:none" id="cancelling-msg-{{build.buildrequest.pk}}"> | 97 | <script id="in-progress-build-template" type="text/x-jsrender"> |
137 | Cancelling the build ... | 98 | <!-- progress bar and task completion percentage --> |
138 | </div> | 99 | <div data-role="build-status" class="col-md-4 col-md-offset-1 progress-info"> |
100 | <!-- progress bar --> | ||
101 | <div class="progress" id="build-pc-done-title-<%:id%>"> | ||
102 | <div id="build-pc-done-bar-<%:id%>" | ||
103 | style="width: <%:tasks_complete_percentage%>%;" | ||
104 | class="progress-bar"> | ||
105 | </div> | ||
106 | </div> | ||
107 | </div> | ||
139 | 108 | ||
140 | <div class="col-md-4 col-md-offset-1 progress-info"> | 109 | <div class="col-md-4 progress-info"> |
141 | <div class="progress" id="build-pc-done-title-{{build.pk}}"> | 110 | <!-- task completion percentage --> |
142 | <div id="build-pc-done-bar-{{build.pk}}" style="width: {{build.completeper}}%;" class="progress-bar"> | 111 | <span id="build-pc-done-<%:id%>"><%:tasks_complete_percentage%></span>% of |
143 | </div> | 112 | tasks complete |
144 | </div> | 113 | <%if is_default_project_build%> |
145 | </div> | 114 | <!-- no cancel icon --> |
115 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue pull-right" title="Builds in this project cannot be cancelled from Toaster: they can only be cancelled from the command line"></span> | ||
116 | <%else%> | ||
117 | <!-- cancel button --> | ||
118 | <span class="cancel-build-btn pull-right alert-link" | ||
119 | data-buildrequest-id="<%:id%>" data-request-url="<%:cancel_url%>"> | ||
120 | <span class="glyphicon glyphicon-remove-circle"></span> | ||
121 | Cancel | ||
122 | </span> | ||
123 | <%/if%> | ||
124 | </div> | ||
125 | </script> | ||
146 | 126 | ||
147 | <div class="col-md-4 progress-info"> | 127 | <!-- cancelling build --> |
148 | <span id="build-pc-done-{{build.pk}}">{{build.completeper}}</span>% of tasks complete | 128 | <script id="cancelling-build-template" type="text/x-jsrender"> |
149 | {# No build cancel for command line builds project #} | 129 | <div class="col-md-9"> |
150 | {% if build.project.is_default %} | 130 | Cancelling the build ... |
151 | <span class="glyphicon glyphicon-question-sign get-help get-help-blue pull-right" title="Builds in this project cannot be cancelled from Toaster: they can only be cancelled from the command line"></span> | 131 | </div> |
152 | {% else %} | 132 | </script> |
153 | <a href="#" class="cancel-build-btn pull-right alert-link" | ||
154 | data-buildrequest-id={{build.buildrequest.pk}} | ||
155 | data-request-url="{% url 'xhr_buildrequest' build.project.pk %}"> | ||
156 | <span class="glyphicon glyphicon-remove-circle"></span> | ||
157 | Cancel | ||
158 | </a> | ||
159 | {% endif %} | ||
160 | </div> | ||
161 | {% endif %} {# end if in progress #} | ||
162 | 133 | ||
163 | {% if build.outcome == build.CANCELLED %} | 134 | <!-- succeeded or failed build --> |
164 | <div class="col-md-6"> | 135 | <script id="succeeded-or-failed-build-template" type="text/x-jsrender"> |
165 | Build cancelled | 136 | <!-- completed_on --> |
166 | </div> | 137 | <div class="col-md-2"> |
138 | <%:completed_on%> | ||
139 | </div> | ||
167 | 140 | ||
168 | <div class="col-md-3"> | 141 | <!-- errors --> |
169 | <a href="#" class="info pull-right run-again-btn alert-link" | 142 | <div class="col-md-2"> |
170 | data-request-url="{% url 'xhr_buildrequest' build.project.pk %}" | 143 | <%if errors%> |
171 | data-target='{{build.target_set.all|get_tasks|json}}'> | 144 | <span class="glyphicon glyphicon-minus-sign"></span> |
172 | <span class="glyphicon glyphicon-repeat"></span> | 145 | <a href="<%:dashboard_errors_url%>" class="alert-link"> |
173 | Rebuild | 146 | <%:errors%> error<%:errors_pluralize%> |
174 | </a> | 147 | </a> |
175 | </div> | 148 | <%/if%> |
176 | {% endif %} | 149 | </div> |
177 | </div> | 150 | |
178 | </div> | 151 | <!-- warnings --> |
179 | {% endfor %} | 152 | <div class="col-md-2"> |
153 | <%if warnings%> | ||
154 | <span class="glyphicon glyphicon-minus-sign"></span> | ||
155 | <a href="<%:dashboard_warnings_url%>" class="alert-link"> | ||
156 | <%:warnings%> warning<%:warnings_pluralize%> | ||
157 | </a> | ||
158 | <%/if%> | ||
159 | </div> | ||
160 | |||
161 | <!-- build time --> | ||
162 | <div class="col-md-3"> | ||
163 | Build time: <a class="alert-link" href="<%:buildtime_url%>"><%:buildtime%></a> | ||
164 | |||
165 | <%if is_default_project_build%> | ||
166 | <!-- info icon --> | ||
167 | <span class="pull-right glyphicon glyphicon-question-sign get-help <%if state == 'Success'%>get-help-green<%else state == 'Failed'%>get-help-red<%else%>get-help-blue<%/if%>" | ||
168 | title="Builds in this project cannot be started from Toaster: they are started from the command line"> | ||
169 | </span> | ||
170 | <%else%> | ||
171 | <!-- rebuild button --> | ||
172 | <span class="rebuild-btn alert-link <%if state == 'Success'%>success<%else state == 'Failed'%>danger<%else%>info<%/if%> pull-right" | ||
173 | data-request-url="<%:rebuild_url%>" data-target='<%:build_targets_json%>'> | ||
174 | <span class="glyphicon glyphicon-repeat"></span> | ||
175 | Rebuild | ||
176 | </span> | ||
177 | <%/if%> | ||
178 | </div> | ||
179 | </script> | ||
180 | |||
181 | <!-- cancelled build --> | ||
182 | <script id="cancelled-build-template" type="text/x-jsrender"> | ||
183 | <!-- build cancelled message --> | ||
184 | <div class="col-md-6"> | ||
185 | Build cancelled | ||
180 | </div> | 186 | </div> |
181 | {% endif %} \ No newline at end of file | 187 | |
188 | <!-- rebuild button --> | ||
189 | <div class="col-md-3"> | ||
190 | <span class="info pull-right rebuild-btn alert-link" | ||
191 | data-request-url="<%:rebuild_url%>" data-target='<%:build_targets_json%>'> | ||
192 | <span class="glyphicon glyphicon-repeat"></span> | ||
193 | Rebuild | ||
194 | </span> | ||
195 | </div> | ||
196 | </script> | ||
197 | |||
198 | <script> | ||
199 | $(document).ready(function () { | ||
200 | var ctx = { | ||
201 | mrbType : "{{mrb_type}}", | ||
202 | } | ||
203 | |||
204 | try { | ||
205 | mrbSectionInit(ctx); | ||
206 | } catch (e) { | ||
207 | document.write("Sorry, An error has occurred loading this page"); | ||
208 | console.warn(e); | ||
209 | } | ||
210 | }); | ||
211 | </script> | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html b/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html index 1fe76a7a24..a5fed2dd41 100644 --- a/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html +++ b/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | <h2 class="top-air" data-role="page-title"></h2> | 25 | <h2 class="top-air" data-role="page-title"></h2> |
26 | 26 | ||
27 | {% if not build_in_progress_none_completed %} | 27 | {% if not build_in_progress_none_completed %} |
28 | {% url 'projectbuilds' project.id as xhr_table_url %} | 28 | {% url 'projectbuilds' project.id as xhr_table_url %} |
29 | {% include 'toastertable.html' %} | 29 | {% include 'toastertable.html' %} |
30 | {% endif %} | 30 | {% endif %} |
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py index dc75f229bb..b170a16165 100644 --- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py +++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py | |||
@@ -271,14 +271,6 @@ def get_dict_value(dictionary, key): | |||
271 | return '' | 271 | return '' |
272 | 272 | ||
273 | @register.filter | 273 | @register.filter |
274 | def format_build_date(completed_on): | ||
275 | now = timezone.now() | ||
276 | delta = now - completed_on | ||
277 | |||
278 | if delta.days >= 1: | ||
279 | return True | ||
280 | |||
281 | @register.filter | ||
282 | def is_shaid(text): | 274 | def is_shaid(text): |
283 | """ return True if text length is 40 characters and all hex-digits | 275 | """ return True if text length is 40 characters and all hex-digits |
284 | """ | 276 | """ |
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 1c0ccbb2e1..9892d2ab93 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
@@ -214,6 +214,9 @@ urlpatterns = patterns('toastergui.views', | |||
214 | api.XhrBuildRequest.as_view(), | 214 | api.XhrBuildRequest.as_view(), |
215 | name='xhr_buildrequest'), | 215 | name='xhr_buildrequest'), |
216 | 216 | ||
217 | url(r'^mostrecentbuilds$', api.MostRecentBuildsView.as_view(), | ||
218 | name='most_recent_builds'), | ||
219 | |||
217 | # default redirection | 220 | # default redirection |
218 | url(r'^$', RedirectView.as_view(url='landing', permanent=True)), | 221 | url(r'^$', RedirectView.as_view(url='landing', permanent=True)), |
219 | ) | 222 | ) |