diff options
16 files changed, 473 insertions, 303 deletions
diff --git a/bitbake/LICENSE b/bitbake/LICENSE index 7a0c272a4a..4a09b0f626 100644 --- a/bitbake/LICENSE +++ b/bitbake/LICENSE | |||
@@ -10,4 +10,6 @@ Foundation and individual contributors. | |||
10 | 10 | ||
11 | * Twitter typeahead.js redistributed under the MIT license. Note that the JS source has one small modification, so the full unminified file is currently included to make it obvious where this is. | 11 | * Twitter typeahead.js redistributed under the MIT license. Note that the JS source has one small modification, so the full unminified file is currently included to make it obvious where this is. |
12 | 12 | ||
13 | * jsrender is redistributed under the MIT license. | ||
14 | |||
13 | * QUnit is redistributed under the MIT license. | 15 | * QUnit is redistributed under the MIT license. |
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 | ) |