summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2014-11-07 13:26:45 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-11-12 17:04:49 +0000
commit7b65fa9bbbee2843e10cf8b8ba8128912100a345 (patch)
tree7ef9b0d29756f4da2e4a3bb0faa660e469d9d883 /bitbake
parentabf7551f60cd56129b9abc22730f45e336ece582 (diff)
downloadpoky-7b65fa9bbbee2843e10cf8b8ba8128912100a345.tar.gz
bitbake: toastergui: changes for the Project page, round 3 of reviews
This patch implements the round 3 of reviews for the Project page, including fixing the time display, fixing the build list display, with fade-in and fade-out animations, and various small layout fixes. [YOCTO #6587] [YOCTO #6731] (Bitbake rev: 09e3ba8f800a03de731b022543cae33a46be17ef) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/lib/toaster/toastergui/static/css/default.css27
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projectapp.js182
-rw-r--r--bitbake/lib/toaster/toastergui/templates/project.html62
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py41
4 files changed, 244 insertions, 68 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/css/default.css b/bitbake/lib/toaster/toastergui/static/css/default.css
index fb20fc9241..da9697c408 100644
--- a/bitbake/lib/toaster/toastergui/static/css/default.css
+++ b/bitbake/lib/toaster/toastergui/static/css/default.css
@@ -113,6 +113,9 @@ select { width: auto; }
113.top-air { margin-top: 40px;} 113.top-air { margin-top: 40px;}
114.progress { margin-bottom: 0px; } 114.progress { margin-bottom: 0px; }
115.lead .badge { font-size: 18px; font-weight: normal; border-radius: 15px; padding: 9px; } 115.lead .badge { font-size: 18px; font-weight: normal; border-radius: 15px; padding: 9px; }
116.lead ol > li, .lead ul > li {
117 line-height: 35px;
118}
116.well > .lead, .alert .lead { margin-bottom: 0px; } 119.well > .lead, .alert .lead { margin-bottom: 0px; }
117.well-transparent { background-color: transparent; } 120.well-transparent { background-color: transparent; }
118.no-results { margin: 10px 0; } 121.no-results { margin: 10px 0; }
@@ -191,3 +194,27 @@ dd > span { line-height: 20px; }
191.new-build form { margin: 5px 0 0; } 194.new-build form { margin: 5px 0 0; }
192.new-build .input-append { margin-bottom: 0; } 195.new-build .input-append { margin-bottom: 0; }
193#build-selected { margin-top: 15px; } 196#build-selected { margin-top: 15px; }
197
198
199.animate-repeat {
200 list-style:none;
201 box-sizing:border-box;
202}
203
204.animate-repeat.ng-move,
205.animate-repeat.ng-enter,
206.animate-repeat.ng-leave {
207 -webkit-transition:all linear 0.5s;
208 transition:all linear 0.5s;
209}
210
211.animate-repeat.ng-leave.ng-leave-active,
212.animate-repeat.ng-move,
213.animate-repeat.ng-enter {
214 opacity:0;
215}
216
217.animate-repeat.ng-leave,
218.animate-repeat.ng-enter.ng-enter-active {
219 opacity:1;
220}
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectapp.js b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
index b347451e88..356b92fc5a 100644
--- a/bitbake/lib/toaster/toastergui/static/js/projectapp.js
+++ b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
@@ -74,17 +74,34 @@ angular_formpost = function($httpProvider) {
74 * 74 *
75 * no return 75 * no return
76 */ 76 */
77function _diffArrays(oldArray, newArray, compareElements, onAdded, onDeleted ) { 77function _diffArrays(existingArray, newArray, compareElements, onAdded, onDeleted ) {
78 if (onDeleted !== undefined) { 78 var added = [];
79 oldArray.filter(function (e) { var found = 0; newArray.map(function (f) { if (compareElements(e, f)) {found = 1};}); return !found;}).map(onDeleted); 79 var removed = [];
80 newArray.forEach( function( newElement, newIndex, _newArray) {
81 var existingIndex = existingArray.findIndex(function ( existingElement, _existingIndex, _existingArray ) {
82 return compareElements(newElement, existingElement);
83 });
84 if (existingIndex < 0 && onAdded) { added.push(newElement); }
85 });
86 existingArray.forEach( function( existingElement, existingIndex, _existingArray) {
87 var newIndex = newArray.findIndex(function ( newElement, _newIndex, _newArray ) {
88 return compareElements(newElement, existingElement);
89 });
90 if (newIndex < 0 && onDeleted) { removed.push(existingElement); }
91 });
92
93 if (onAdded) {
94 added.map(onAdded);
80 } 95 }
81 if (onAdded !== undefined) { 96
82 newArray.filter(function (e) { var found = 0; oldArray.map(function (f) { if (compareElements(e, f)) {found = 1};}); return !found;}).map(onAdded); 97 if (onDeleted) {
98 removed.map(onDeleted);
83 } 99 }
100
84} 101}
85 102
86 103
87var projectApp = angular.module('project', ['ui.bootstrap', 'ngCookies'], angular_formpost); 104var projectApp = angular.module('project', ['ngCookies', 'ngAnimate', 'ui.bootstrap' ], angular_formpost);
88 105
89// modify the template tag markers to prevent conflicts with Django 106// modify the template tag markers to prevent conflicts with Django
90projectApp.config(function($interpolateProvider) { 107projectApp.config(function($interpolateProvider) {
@@ -111,7 +128,7 @@ projectApp.filter('timediff', function() {
111 128
112 129
113// main controller for the project page 130// main controller for the project page
114projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $q, $sce) { 131projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $q, $sce, $anchorScroll, $animate) {
115 132
116 $scope.getSuggestions = function(type, currentValue) { 133 $scope.getSuggestions = function(type, currentValue) {
117 var deffered = $q.defer(); 134 var deffered = $q.defer();
@@ -159,40 +176,65 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
159 deffered.reject(_data.error); 176 deffered.reject(_data.error);
160 } 177 }
161 else { 178 else {
162 // TODO: update screen data if we have fields here
163 179
164 if (_data.builds !== undefined) { 180 if (_data.builds !== undefined) {
165 181 var toDelete = [];
166 var oldbuilds = $scope.builds; 182 // step 1 - delete entries not found
167 $scope.builds = _data.builds; 183 $scope.builds.forEach(function (elem) {
168 184 if (-1 == _data.builds.findIndex(function (elemX) { return elemX.id == elem.id && elemX.status == elem.status; })) {
169 // identify canceled builds here, so we can display them. 185 toDelete.push(elem);
170 _diffArrays(oldbuilds, $scope.builds, 186 }
171 function (e,f) { return e.id == f.id }, // compare 187 });
172 undefined, // added 188 toDelete.forEach(function (elem) {
173 function (e) { // deleted 189 $scope.builds.splice($scope.builds.indexOf(elem),1);
174 if (e.status == "deleted") return; 190 });
175 e.status = "deleted"; 191 // step 2 - merge new entries
176 for (var i = 0; i < $scope.builds.length; i++) { 192 _data.builds.forEach(function (elem) {
177 if ($scope.builds[i].status == "queued" && $scope.builds[i].id > e.id) 193 var found = false;
178 continue; 194 var i = 0;
179 $scope.builds.splice(i, 0, e); 195 for (i = 0 ; i < $scope.builds.length; i ++) {
180 break; 196 if ($scope.builds[i].id > elem.id) continue;
181 } 197 if ($scope.builds[i].id == elem.id) { found=true; break;}
182 }); 198 if ($scope.builds[i].id < elem.id) break;
199 }
200 if (!found) {
201 $scope.builds.splice(i, 0, elem);
202 }
203 });
183 204
184 } 205 }
185 if (_data.layers !== undefined) { 206 if (_data.layers !== undefined) {
186 var oldlayers = $scope.layers;
187 $scope.layers = _data.layers;
188 207
189 // show added/deleted layer notifications
190 var addedLayers = []; 208 var addedLayers = [];
191 var deletedLayers = []; 209 var deletedLayers = [];
192 _diffArrays( oldlayers, $scope.layers, function (e, f) { return e.id == f.id },
193 function (e) { console.log("new layer", e);addedLayers.push(e); },
194 function (e) { console.log("del layer", e);deletedLayers.push(e); });
195 210
211 // step 1 - delete entries not found
212 $scope.layers.forEach(function (elem) {
213 if (-1 == _data.layers.findIndex(function (elemX) { return elemX.id == elem.id && elemX.name == elem.name; })) {
214 deletedLayers.push(elem);
215 }
216 });
217 deletedLayers.forEach(function (elem) {
218 $scope.layers.splice($scope.layers.indexOf(elem),1);
219 });
220 // step 2 - merge new entries
221 _data.layers.forEach(function (elem) {
222 var found = false;
223 var i;
224 for (i = 0 ; i < $scope.layers.length; i ++) {
225 if ($scope.layers[i].orderid < elem.orderid) continue;
226 if ($scope.layers[i].orderid == elem.orderid) {
227 found = true; break;
228 }
229 if ($scope.layers[i].orderid > elem.orderid) break;
230 }
231 if (!found) {
232 $scope.layers.splice(i, 0, elem);
233 addedLayers.push(elem);
234 }
235 });
236
237 // step 3 - display alerts.
196 if (addedLayers.length > 0) { 238 if (addedLayers.length > 0) {
197 $scope.displayAlert($scope.zone2alerts, "You have added <b>"+addedLayers.length+"</b> layer" + ((addedLayers.length>1)?"s: ":": ") + addedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", "), "alert-info"); 239 $scope.displayAlert($scope.zone2alerts, "You have added <b>"+addedLayers.length+"</b> layer" + ((addedLayers.length>1)?"s: ":": ") + addedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", "), "alert-info");
198 } 240 }
@@ -253,7 +295,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
253 } 295 }
254 296
255 $scope.targetNamedBuild = function(target) { 297 $scope.targetNamedBuild = function(target) {
256 if ($scope.targetName === undefined){ 298 if ($scope.targetName === undefined && $scope.targetName1 === undefined){
257 alert("No target defined, please type in a target name"); 299 alert("No target defined, please type in a target name");
258 return; 300 return;
259 } 301 }
@@ -263,17 +305,26 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
263 $scope._makeXHRCall({ 305 $scope._makeXHRCall({
264 method: "POST", url: $scope.urls.xhr_build, 306 method: "POST", url: $scope.urls.xhr_build,
265 data : { 307 data : {
266 targets: $scope.targetName 308 targets: $scope.safeTargetName,
267 } 309 }
268 }).then(function (data) { 310 }).then(function (data) {
269 console.log("received ", data); 311 console.log("received ", data);
270 $scope.targetName = undefined; 312 $scope.targetName = undefined;
313 $scope.targetName1 = undefined;
314 $location.hash('buildslist');
315 // call $anchorScroll()
316 $anchorScroll();
271 }); 317 });
272 } 318 }
273 319
274 $scope.sanitizeTargetName = function() { 320 $scope.sanitizeTargetName = function() {
275 if (undefined === $scope.targetName) return; 321 $scope.safeTargetName = undefined;
276 $scope.targetName = $scope.targetName.replace(/\[.*\]/, '').trim(); 322 if (undefined === $scope.targetName) $scope.safeTargetName = $scope.targetName1;
323 if (undefined === $scope.targetName1) $scope.safeTargetName = $scope.targetName;
324
325 if (undefined === $scope.safeTargetName) return;
326
327 $scope.safeTargetName = $scope.safeTargetName.replace(/\[.*\]/, '').trim();
277 } 328 }
278 329
279 $scope.buildCancel = function(id) { 330 $scope.buildCancel = function(id) {
@@ -285,6 +336,16 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
285 }); 336 });
286 } 337 }
287 338
339 $scope.buildDelete = function(id) {
340 $scope._makeXHRCall({
341 method: "POST", url: $scope.urls.xhr_build,
342 data: {
343 buildDelete: id,
344 }
345 });
346 }
347
348
288 $scope.onLayerSelect = function (item, model, label) { 349 $scope.onLayerSelect = function (item, model, label) {
289 $scope.layerAddId = item.id; 350 $scope.layerAddId = item.id;
290 } 351 }
@@ -413,6 +474,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
413 console.log("edit with ", elementid); 474 console.log("edit with ", elementid);
414 var alertText = undefined; 475 var alertText = undefined;
415 var alertZone = undefined; 476 var alertZone = undefined;
477 var oldLayers = [];
416 switch(elementid) { 478 switch(elementid) {
417 case '#select-machine': 479 case '#select-machine':
418 alertText = "You have changed the machine to: <b>" + $scope.machineName + "</b>"; 480 alertText = "You have changed the machine to: <b>" + $scope.machineName + "</b>";
@@ -428,25 +490,61 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
428 data['projectVersion'] = $scope.projectVersion; 490 data['projectVersion'] = $scope.projectVersion;
429 alertText = "You have changed the release to: "; 491 alertText = "You have changed the release to: ";
430 alertZone = $scope.zone3alerts; 492 alertZone = $scope.zone3alerts;
493 // save old layers
494 oldLayers = $scope.layers.slice(0);
431 break; 495 break;
432 default: 496 default:
433 throw "FIXME: implement conversion for element " + elementid; 497 throw "FIXME: implement conversion for element " + elementid;
434 } 498 }
435 499
436 console.log("calling edit with ", data);
437 $scope._makeXHRCall({ 500 $scope._makeXHRCall({
438 method: "POST", url: $scope.urls.xhr_edit, data: data, 501 method: "POST", url: $scope.urls.xhr_edit, data: data,
439 }).then( function () { 502 }).then( function (_data) {
440 $scope.toggle(elementid); 503 $scope.toggle(elementid);
441 if (data['projectVersion'] != undefined) { 504 if (data['projectVersion'] != undefined) {
442 alertText += "<b>" + $scope.project.release.name + "</b>"; 505 alertText += "<strong>" + $scope.project.release.desc + "</strong>. ";
506 }
507 if (elementid == '#change-project-version') {
508 // requirement https://bugzilla.yoctoproject.org/attachment.cgi?id=2229, notification for changed version to include layers
509 $scope.zone2alerts.forEach(function (e) { e.close() });
510 alertText += "This has caused the following changes in your project layers:<ul>"
511
512 if (_data.layers !== undefined) {
513 // show added/deleted layer notifications; scope.layers is already updated by this point.
514 var addedLayers = [];
515 var deletedLayers = [];
516 _diffArrays( oldLayers, $scope.layers, function (e, f) { return e.id == f.id },
517 function (e) {addedLayers.push(e); },
518 function (e) {deletedLayers.push(e); });
519
520 // some of the deleted layers are actually replaced (changed) layers
521 var changedLayers = [];
522 deletedLayers.forEach(function (e) {
523 if ( -1 < addedLayers.findIndex(function (f) { return f.name == e.name })) {
524 changedLayers.push(e);
525 }
526 });
527
528 changedLayers.forEach(function (e) {
529 deletedLayers.splice(deletedLayers.indexOf(e), 1);
530 });
531
532 if (addedLayers.length > 0) {
533 alertText += "<li><strong>"+addedLayers.length+"</strong> layer" + ((addedLayers.length>1)?"s changed: ":" changed: ") + addedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", ") + "</li>";
534 }
535 if (deletedLayers.length > 0) {
536 alertText += "<li><strong>"+deletedLayers.length+"</strong> layer" + ((deletedLayers.length>1)?"s deleted: ":"deleted: ") + deletedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", ") + "</li>";
537 }
538
539 }
540 alertText += "</ul>";
443 } 541 }
444 $scope.displayAlert(alertZone, alertText, "alert-info"); 542 $scope.displayAlert(alertZone, alertText, "alert-info");
445 }); 543 });
446 } 544 }
447 545
448 546
449 $scope.executeCommands = function() { 547 $scope.updateDisplayWithCommands = function() {
450 cmd = $location.path(); 548 cmd = $location.path();
451 549
452 function _cmdExecuteWithParam(param, f) { 550 function _cmdExecuteWithParam(param, f) {
@@ -524,7 +622,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
524 // init code 622 // init code
525 // 623 //
526 $scope.init = function() { 624 $scope.init = function() {
527 $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "GET", url: $scope.urls.xhr_edit, data: undefined});}, 4000, 0); 625 $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "GET", url: $scope.urls.xhr_edit, data: undefined});}, 2000, 0);
528 } 626 }
529 627
530 $scope.init(); 628 $scope.init();
@@ -539,6 +637,8 @@ function test_diff_arrays() {
539 _diffArrays([1,2,3], [2,3,4], function(e,f) { return e==f; }, function(e) {console.log("added", e)}, function(e) {console.log("deleted", e);}) 637 _diffArrays([1,2,3], [2,3,4], function(e,f) { return e==f; }, function(e) {console.log("added", e)}, function(e) {console.log("deleted", e);})
540} 638}
541 639
640// test_diff_arrays();
641
542var s = undefined; 642var s = undefined;
543 643
544function test_set_alert(text) { 644function test_set_alert(text) {
diff --git a/bitbake/lib/toaster/toastergui/templates/project.html b/bitbake/lib/toaster/toastergui/templates/project.html
index 6a812834d3..a8f2d6ad4f 100644
--- a/bitbake/lib/toaster/toastergui/templates/project.html
+++ b/bitbake/lib/toaster/toastergui/templates/project.html
@@ -9,6 +9,7 @@ vim: expandtab tabstop=2
9 9
10{% block projectinfomain %} 10{% block projectinfomain %}
11<script src="{% static "js/angular.min.js" %}"></script> 11<script src="{% static "js/angular.min.js" %}"></script>
12<script src="{% static "js/angular-animate.min.js" %}"></script>
12<script src="{% static "js/angular-cookies.min.js" %}"></script> 13<script src="{% static "js/angular-cookies.min.js" %}"></script>
13<script src="{% static "js/ui-bootstrap-tpls-0.11.0.js" %}"></script> 14<script src="{% static "js/ui-bootstrap-tpls-0.11.0.js" %}"></script>
14 15
@@ -105,19 +106,21 @@ vim: expandtab tabstop=2
105 </form> 106 </form>
106 </div> 107 </div>
107 108
109 <a id="buildslist"></a>
108 <h2 class="air" ng-if="builds.length">Latest builds</h2> 110 <h2 class="air" ng-if="builds.length">Latest builds</h2>
109 111 <div class="animate-repeat alert" ng-repeat="b in builds track by b.id" ng-class="{'queued':'alert-info', 'deleted':'alert-info', 'in progress': 'alert-info', 'failed':'alert-error', 'completed':{'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.build[0].status]}[b.status]">
110 <div class="alert" ng-repeat="b in builds" ng-class="{'queued':'alert-info', 'deleted':'alert-info', 'in progress': 'alert-info', 'failed':'alert-error', 'completed':{'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.build[0].status]}[b.status]" >
111 <div class="row-fluid"> 112 <div class="row-fluid">
112 <switch ng-switch="b.status"> 113 <switch ng-switch="b.status">
114
113 <case ng-switch-when="failed"> 115 <case ng-switch-when="failed">
114 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div> 116 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span></div>
115 <div class="row-fluid"> 117 <div class="row-fluid">
116 <div class="air well" ng-repeat="e in b.errors"> 118 <div class="air well" ng-repeat="e in b.errors">
117 {[e.type]}: <pre>{[e.msg]}</pre> 119 Error type {[e.type]}: <pre>{[e.msg]}</pre>
118 </div> 120 </div>
119 </div> 121 </div>
120 </case> 122 </case>
123
121 <case ng-switch-when="queued"> 124 <case ng-switch-when="queued">
122 <div class="lead span5"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div> 125 <div class="lead span5"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
123 <div class="span4 lead" >Build queued 126 <div class="span4 lead" >Build queued
@@ -125,6 +128,7 @@ vim: expandtab tabstop=2
125 </div> 128 </div>
126 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button> 129 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button>
127 </case> 130 </case>
131
128 <case ng-switch-when="created"> 132 <case ng-switch-when="created">
129 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div> 133 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
130 <div class="span6" > 134 <div class="span6" >
@@ -132,35 +136,56 @@ vim: expandtab tabstop=2
132 </div> 136 </div>
133 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button> 137 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button>
134 </case> 138 </case>
139
135 <case ng-switch-when="deleted"> 140 <case ng-switch-when="deleted">
136 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div> 141 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
137 <div class="span6" id="{[b.id]}-deleted" > 142 <div class="span6" id="{[b.id]}-deleted" >
138 <span class="lead">Build deleted</span> 143 <span class="lead">Build deleted</span>
139 </div> 144 </div>
140 <button class="btn pull-right btn-info" ng-click="builds.splice(builds.indexOf(b), 1)">Close</button> 145 <button class="btn pull-right btn-info" ng-click="buildDelete(b.id)">Close</button>
141 </case> 146 </case>
147
148
142 <case ng-switch-when="in progress"> 149 <case ng-switch-when="in progress">
143 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div> 150 <switch ng-switch="b.build.length">
144 <div class="span4" > 151 <case ng-switch-when="0">
145 <div class="progress" style="margin-top:5px;" data-toggle="tooltip" tooltip="{[b.build[0].completeper]}% of tasks complete"> 152 <div class="lead span5"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
146 <div style="width: {[b.build[0].completeper]}%;" class="bar"></div> 153 <div class="span4 lead">
154 Checking out layers
147 </div> 155 </div>
148 </div> 156 </case>
149 <div class="lead pull-right">ETA: at {[b.build[0].eta|date:"shortDate"]}</div> 157 <case ng-switch-default="">
158 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
159 <div class="span4 offset1" >
160 <div class="progress" style="margin-top:5px;" data-toggle="tooltip" tooltip="{[b.build[0].completeper]}% of tasks complete">
161 <div style="width: {[b.build[0].completeper]}%;" class="bar"></div>
162 </div>
163 </div>
164 <div class="text-right lead">ETA: {[b.build[0].eta|date:"HH:mm:ss"]}</div>
165 </case>
150 </case> 166 </case>
167
168
151 <case ng-switch-when="completed"> 169 <case ng-switch-when="completed">
152 <div class="lead span3"><a href="{[b.build[0].build_page_url]}"><span ng-repeat="t in b.targets" ng-include src="'target_display'"></span></a></div> 170 <div class="lead span3"><a href="{[b.build[0].build_page_url]}"><span ng-repeat="t in b.targets" ng-include src="'target_display'"></span></a></div>
153 <div class="span2 lead"> 171 <div class="span2 lead">
154 {[b.build[0].completed_on|date:'dd/MM/yy HH:mm']} 172 <ngif ng-if="b.build[0].completed_on - todaydate > 0">
173 {[b.build[0].completed_on|date:'HH:mm']}
174 </ngif>
175 <ngif ng-if="b.build[0].completed_on - todaydate < 0">
176 {[b.build[0].completed_on|date:'dd/MM/yy HH:mm']}
177 </ngif>
155 </div> 178 </div>
156 <div class="span2"><span><a href="{[b.build[0].build_page_url]}#errors" class="lead error" ng-if="b.build[0].errors">{[b.build[0].errors]}</a></span></div> 179 <div class="span2"><span><a href="{[b.build[0].build_page_url]}#errors" class="lead error" ng-if="b.build[0].errors">{[b.build[0].errors]}</a></span></div>
157 <div class="span2"><span><a href="{[b.build[0].build_page_url]}#warnings" class="lead warning" ng-if="b.build[0].warnings">{[b.build[0].warnings]}</a></span></div> 180 <div class="span2"><span><a href="{[b.build[0].build_page_url]}#warnings" class="lead warning" ng-if="b.build[0].warnings">{[b.build[0].warnings]}</a></span></div>
158 <div> <span class="lead">Build time: {[b.build[0].build_time|timediff]}</span> 181 <div> <span class="lead">Build time: <a href="{[b.build[0].build_time_page_url]}">{[b.build[0].build_time|timediff]}</a></span>
159 <button class="btn pull-right" ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]" 182 <button class="btn pull-right" ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]"
160 ng-click="targetExistingBuild(b.targets)">Run again</button> 183 ng-click="targetExistingBuild(b.targets)">Run again</button>
161 184
162 </div> 185 </div>
163 </case> 186 </case>
187
188
164 <case ng-switch-default=""> 189 <case ng-switch-default="">
165 <div>FIXME!</div> 190 <div>FIXME!</div>
166 </case> 191 </case>
@@ -206,7 +231,7 @@ vim: expandtab tabstop=2
206 </form> 231 </form>
207 <p><a href="{% url 'layers' %}">View all layers</a> | <a href="{% url 'importlayer' %}">Import layer</a></p> 232 <p><a href="{% url 'layers' %}">View all layers</a> | <a href="{% url 'importlayer' %}">Import layer</a></p>
208 <ul class="unstyled configuration-list"> 233 <ul class="unstyled configuration-list">
209 <li ng-repeat="l in layers"> 234 <li ng-repeat="l in layers track by l.id" class="animate-repeat">
210 <a href="{[l.layerdetailurl]}" target="_#" class="layer-info" data-toggle="tooltip" tooltip="{[l.branch.layersource]} | {[l.branch.name]}">{[l.name]} </a> 235 <a href="{[l.layerdetailurl]}" target="_#" class="layer-info" data-toggle="tooltip" tooltip="{[l.branch.layersource]} | {[l.branch.name]}">{[l.name]} </a>
211 <i class="icon-trash" ng-click="layerDel(l.id)" tooltip="Delete"></i> 236 <i class="icon-trash" ng-click="layerDel(l.id)" tooltip="Delete"></i>
212 </li> 237 </li>
@@ -221,8 +246,8 @@ vim: expandtab tabstop=2
221 <i class="icon-question-sign get-help heading-help" title="What you build, often a recipe producing a root file system file (an image). Something like <code>core-image-minimal</code> or <code>core-image-sato</code>"></i> 246 <i class="icon-question-sign get-help heading-help" title="What you build, often a recipe producing a root file system file (an image). Something like <code>core-image-minimal</code> or <code>core-image-sato</code>"></i>
222 </h3> 247 </h3>
223 <form ng-submit="targetNamedBuild()" class="input-append"> 248 <form ng-submit="targetNamedBuild()" class="input-append">
224 <input type="text" class="input-xlarge" placeholder="Type the target(s) you want to build" autocomplete="off" data-minLength="1" ng-model="targetName" typeahead="e.name for e in getSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length"> 249 <input type="text" class="input-xlarge" placeholder="Type the target(s) you want to build" autocomplete="off" data-minLength="1" ng-model="targetName1" typeahead="e.name for e in getSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length">
225 <button type="submit" id="build-button" class="btn btn-primary" ng-disabled="!targetName.length"> 250 <button type="submit" id="build-button" class="btn btn-primary" ng-disabled="!targetName1.length">
226 Build </button> 251 Build </button>
227 {% csrf_token %} 252 {% csrf_token %}
228 </form> 253 </form>
@@ -343,13 +368,16 @@ angular.element(document).ready(function() {
343 scope.machine = {{machine|safe}}; 368 scope.machine = {{machine|safe}};
344 scope.releases = {{releases|safe}}; 369 scope.releases = {{releases|safe}};
345 370
371 var now = (new Date()).getTime();
372 scope.todaydate = now - (now % 86400000);
373
346 scope.zone1alerts = []; 374 scope.zone1alerts = [];
347 scope.zone2alerts = []; 375 scope.zone2alerts = [];
348 scope.zone3alerts = []; 376 scope.zone3alerts = [];
349 377
350 scope.mostBuiltTargets = {}; 378 scope.mostBuiltTargets = {};
351 379
352 scope.executeCommands(); 380 scope.updateDisplayWithCommands();
353 scope.validateData(); 381 scope.validateData();
354 382
355 scope.$digest(); 383 scope.$digest();
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index fb8075067a..3b29dbcfb2 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -1943,11 +1943,13 @@ if toastermain.settings.MANAGED:
1943 "completed_on" : y.completed_on.strftime('%s')+"000", 1943 "completed_on" : y.completed_on.strftime('%s')+"000",
1944 "build_time" : (y.completed_on - y.started_on).total_seconds(), 1944 "build_time" : (y.completed_on - y.started_on).total_seconds(),
1945 "build_page_url" : reverse('builddashboard', args=(y.pk,)), 1945 "build_page_url" : reverse('builddashboard', args=(y.pk,)),
1946 'build_time_page_url': reverse('buildtime', args=(y.pk,)),
1946 "errors": y.errors_no, 1947 "errors": y.errors_no,
1947 "warnings": y.warnings_no, 1948 "warnings": y.warnings_no,
1948 "completeper": y.completeper(), 1949 "completeper": y.completeper(),
1949 "eta": y.eta().ctime()}, Build.objects.filter(buildrequest = x)), 1950 "eta": y.eta().strftime('%s')+"000"}, Build.objects.filter(buildrequest = x)),
1950 }, prj.buildrequest_set.order_by("-pk")[:5]) 1951 }, list(prj.buildrequest_set.filter(Q(state__lt=BuildRequest.REQ_COMPLETED) or Q(state=BuildRequest.REQ_DELETED)).order_by("-pk")) +
1952 list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3]))
1951 1953
1952 1954
1953 # Shows the edit project page 1955 # Shows the edit project page
@@ -1979,10 +1981,17 @@ if toastermain.settings.MANAGED:
1979 context = { 1981 context = {
1980 "project" : prj, 1982 "project" : prj,
1981 "completedbuilds": Build.objects.filter(project = prj).exclude(outcome = Build.IN_PROGRESS), 1983 "completedbuilds": Build.objects.filter(project = prj).exclude(outcome = Build.IN_PROGRESS),
1982 "prj" : json.dumps({"name": prj.name, "release": { "id": prj.release.pk, "name": prj.release.name}}), 1984 "prj" : json.dumps({"name": prj.name, "release": { "id": prj.release.pk, "name": prj.release.name, "desc": prj.release.description}}),
1983 #"buildrequests" : prj.buildrequest_set.filter(state=BuildRequest.REQ_QUEUED), 1985 #"buildrequests" : prj.buildrequest_set.filter(state=BuildRequest.REQ_QUEUED),
1984 "builds" : json.dumps(_project_recent_build_list(prj)), 1986 "builds" : json.dumps(_project_recent_build_list(prj)),
1985 "layers" : json.dumps(map(lambda x: {"id": x.layercommit.pk, "name" : x.layercommit.layer.name, "url": x.layercommit.layer.layer_index_url, "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, prj.projectlayer_set.all())), 1987 "layers" : json.dumps(map(lambda x: {
1988 "id": x.layercommit.pk,
1989 "orderid": x.pk,
1990 "name" : x.layercommit.layer.name,
1991 "url": x.layercommit.layer.layer_index_url,
1992 "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)),
1993 "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}},
1994 prj.projectlayer_set.all().order_by("id"))),
1986 "targets" : json.dumps(map(lambda x: {"target" : x.target, "task" : x.task, "pk": x.pk}, prj.projecttarget_set.all())), 1995 "targets" : json.dumps(map(lambda x: {"target" : x.target, "task" : x.task, "pk": x.pk}, prj.projecttarget_set.all())),
1987 "freqtargets": json.dumps(freqtargets), 1996 "freqtargets": json.dumps(freqtargets),
1988 "releases": json.dumps(map(lambda x: {"id": x.pk, "name": x.name}, Release.objects.all())), 1997 "releases": json.dumps(map(lambda x: {"id": x.pk, "name": x.name}, Release.objects.all())),
@@ -2012,12 +2021,17 @@ if toastermain.settings.MANAGED:
2012 for i in request.POST['buildCancel'].strip().split(" "): 2021 for i in request.POST['buildCancel'].strip().split(" "):
2013 try: 2022 try:
2014 br = BuildRequest.objects.select_for_update().get(project = prj, pk = i, state__lte = BuildRequest.REQ_QUEUED) 2023 br = BuildRequest.objects.select_for_update().get(project = prj, pk = i, state__lte = BuildRequest.REQ_QUEUED)
2015 print "selected for delete", br.pk 2024 br.state = BuildRequest.REQ_DELETED
2016 br.delete() 2025 br.save()
2017 print "selected for delete", br.pk
2018 except BuildRequest.DoesNotExist: 2026 except BuildRequest.DoesNotExist:
2019 pass 2027 pass
2020 2028
2029 if 'buildDelete' in request.POST:
2030 for i in request.POST['buildDelete'].strip().split(" "):
2031 try:
2032 br = BuildRequest.objects.select_for_update().get(project = prj, pk = i, state__lte = BuildRequest.REQ_DELETED).delete()
2033 except BuildRequest.DoesNotExist:
2034 pass
2021 2035
2022 if 'targets' in request.POST: 2036 if 'targets' in request.POST:
2023 ProjectTarget.objects.filter(project = prj).delete() 2037 ProjectTarget.objects.filter(project = prj).delete()
@@ -2054,9 +2068,10 @@ if toastermain.settings.MANAGED:
2054 prj.name = request.POST['projectName'] 2068 prj.name = request.POST['projectName']
2055 prj.save(); 2069 prj.save();
2056 2070
2057
2058 if 'projectVersion' in request.POST: 2071 if 'projectVersion' in request.POST:
2059 prj.release = Release.objects.get(pk = request.POST['projectVersion']) 2072 prj.release = Release.objects.get(pk = request.POST['projectVersion'])
2073 # we need to change the bitbake version
2074 prj.bitbake_version = prj.release.bitbake_version
2060 prj.save() 2075 prj.save()
2061 # we need to change the layers 2076 # we need to change the layers
2062 for i in prj.projectlayer_set.all(): 2077 for i in prj.projectlayer_set.all():
@@ -2067,13 +2082,19 @@ if toastermain.settings.MANAGED:
2067 # get rid of the old entry 2082 # get rid of the old entry
2068 i.delete() 2083 i.delete()
2069 2084
2085 if 'machineName' in request.POST:
2086 machinevar = prj.projectvariable_set.get(name="MACHINE")
2087 machinevar.value=request.POST['machineName']
2088 machinevar.save()
2089
2070 # return all project settings 2090 # return all project settings
2071 return HttpResponse(json.dumps( { 2091 return HttpResponse(json.dumps( {
2072 "error": "ok", 2092 "error": "ok",
2073 "layers" : map(lambda x: {"id": x.layercommit.pk, "name" : x.layercommit.layer.name, "url": x.layercommit.layer.layer_index_url, "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, prj.projectlayer_set.all()), 2093 "layers" : map(lambda x: {"id": x.layercommit.pk, "orderid" : x.pk, "name" : x.layercommit.layer.name, "url": x.layercommit.layer.layer_index_url, "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, prj.projectlayer_set.all().order_by("id")),
2074 "builds" : _project_recent_build_list(prj), 2094 "builds" : _project_recent_build_list(prj),
2075 "variables": map(lambda x: (x.name, x.value), prj.projectvariable_set.all()), 2095 "variables": map(lambda x: (x.name, x.value), prj.projectvariable_set.all()),
2076 "prj": {"name": prj.name, "release": { "id": prj.release.pk, "name": prj.release.name}}, 2096 "machine": {"name": prj.projectvariable_set.get(name="MACHINE").value},
2097 "prj": {"name": prj.name, "release": { "id": prj.release.pk, "name": prj.release.name, "desc": prj.release.description}},
2077 }), content_type = "application/json") 2098 }), content_type = "application/json")
2078 2099
2079 except Exception as e: 2100 except Exception as e: