diff options
| -rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/projectapp.js | 234 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/project.html | 50 | ||||
| -rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 97 |
3 files changed, 246 insertions, 135 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectapp.js b/bitbake/lib/toaster/toastergui/static/js/projectapp.js index 767ea13a7e..0bdc55a733 100644 --- a/bitbake/lib/toaster/toastergui/static/js/projectapp.js +++ b/bitbake/lib/toaster/toastergui/static/js/projectapp.js | |||
| @@ -100,6 +100,16 @@ function _diffArrays(existingArray, newArray, compareElements, onAdded, onDelete | |||
| 100 | 100 | ||
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | // add Array findIndex if not there | ||
| 104 | |||
| 105 | if (Array.prototype.findIndex === undefined) { | ||
| 106 | Array.prototype.findIndex = function (callback) { | ||
| 107 | var i = 0; | ||
| 108 | for ( i = 0; i < this.length; i++ ) | ||
| 109 | if (callback(this[i], i, this)) return i; | ||
| 110 | return -1; | ||
| 111 | } | ||
| 112 | } | ||
| 103 | 113 | ||
| 104 | var projectApp = angular.module('project', ['ngCookies', 'ngAnimate', 'ui.bootstrap', 'ngRoute', 'ngSanitize'], angular_formpost); | 114 | var projectApp = angular.module('project', ['ngCookies', 'ngAnimate', 'ui.bootstrap', 'ngRoute', 'ngSanitize'], angular_formpost); |
| 105 | 115 | ||
| @@ -126,11 +136,17 @@ projectApp.filter('timediff', function() { | |||
| 126 | } | 136 | } |
| 127 | }); | 137 | }); |
| 128 | 138 | ||
| 139 | /** | ||
| 140 | * main controller for the project page | ||
| 141 | */ | ||
| 129 | 142 | ||
| 130 | // main controller for the project page | ||
| 131 | projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $cookieStore, $q, $sce, $anchorScroll, $animate, $sanitize) { | 143 | projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $cookieStore, $q, $sce, $anchorScroll, $animate, $sanitize) { |
| 132 | 144 | ||
| 133 | $scope.getSuggestions = function(type, currentValue) { | 145 | /** |
| 146 | * Retrieves text suggestions for text-edit drop down autocomplete boxes | ||
| 147 | */ | ||
| 148 | |||
| 149 | $scope.getAutocompleteSuggestions = function(type, currentValue) { | ||
| 134 | var deffered = $q.defer(); | 150 | var deffered = $q.defer(); |
| 135 | 151 | ||
| 136 | $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: type, value: currentValue}}) | 152 | $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: type, value: currentValue}}) |
| @@ -147,17 +163,19 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 147 | 163 | ||
| 148 | var inXHRcall = false; | 164 | var inXHRcall = false; |
| 149 | 165 | ||
| 150 | // default handling of XHR calls that handles errors and updates commonly-used pages | 166 | /** |
| 167 | * XHR call wrapper that automatically handles errors and auto-updates the page content to reflect project state on server side. | ||
| 168 | */ | ||
| 151 | $scope._makeXHRCall = function(callparams) { | 169 | $scope._makeXHRCall = function(callparams) { |
| 152 | if (inXHRcall) { | 170 | if (inXHRcall) { |
| 153 | if (callparams.data === undefined) { | 171 | if (callparams.data === undefined) { |
| 154 | // we simply skip the data refresh calls | 172 | // we simply skip the data refresh calls |
| 155 | console.warn("race on XHR, aborted"); | 173 | console.warn("TRC1: race on XHR, aborted"); |
| 156 | return; | 174 | return; |
| 157 | } else { | 175 | } else { |
| 158 | // we return a promise that we'll solve by reissuing the command later | 176 | // we return a promise that we'll solve by reissuing the command later |
| 159 | var delayed = $q.defer(); | 177 | var delayed = $q.defer(); |
| 160 | console.warn("race on XHR, delayed"); | 178 | console.warn("TRC2: race on XHR, delayed"); |
| 161 | $interval(function () {$scope._makeXHRCall(callparams).then(function (d) { delayed.resolve(d); });}, 100, 1); | 179 | $interval(function () {$scope._makeXHRCall(callparams).then(function (d) { delayed.resolve(d); });}, 100, 1); |
| 162 | 180 | ||
| 163 | return delayed.promise; | 181 | return delayed.promise; |
| @@ -178,33 +196,6 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 178 | deffered.reject(_data.error); | 196 | deffered.reject(_data.error); |
| 179 | } | 197 | } |
| 180 | else { | 198 | else { |
| 181 | |||
| 182 | if (_data.builds !== undefined) { | ||
| 183 | var toDelete = []; | ||
| 184 | // step 1 - delete entries not found | ||
| 185 | $scope.builds.forEach(function (elem) { | ||
| 186 | if (-1 == _data.builds.findIndex(function (elemX) { return elemX.id == elem.id && elemX.status == elem.status; })) { | ||
| 187 | toDelete.push(elem); | ||
| 188 | } | ||
| 189 | }); | ||
| 190 | toDelete.forEach(function (elem) { | ||
| 191 | $scope.builds.splice($scope.builds.indexOf(elem),1); | ||
| 192 | }); | ||
| 193 | // step 2 - merge new entries | ||
| 194 | _data.builds.forEach(function (elem) { | ||
| 195 | var found = false; | ||
| 196 | var i = 0; | ||
| 197 | for (i = 0 ; i < $scope.builds.length; i ++) { | ||
| 198 | if ($scope.builds[i].id > elem.id) continue; | ||
| 199 | if ($scope.builds[i].id == elem.id) { found=true; break;} | ||
| 200 | if ($scope.builds[i].id < elem.id) break; | ||
| 201 | } | ||
| 202 | if (!found) { | ||
| 203 | $scope.builds.splice(i, 0, elem); | ||
| 204 | } | ||
| 205 | }); | ||
| 206 | |||
| 207 | } | ||
| 208 | if (_data.layers !== undefined) { | 199 | if (_data.layers !== undefined) { |
| 209 | 200 | ||
| 210 | var addedLayers = []; | 201 | var addedLayers = []; |
| @@ -239,12 +230,59 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 239 | // step 3 - display alerts. | 230 | // step 3 - display alerts. |
| 240 | if (addedLayers.length > 0) { | 231 | if (addedLayers.length > 0) { |
| 241 | $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"); | 232 | $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"); |
| 233 | // invalidate error layer data based on current layers | ||
| 234 | $scope.layersForTargets = {}; | ||
| 242 | } | 235 | } |
| 243 | if (deletedLayers.length > 0) { | 236 | if (deletedLayers.length > 0) { |
| 244 | $scope.displayAlert($scope.zone2alerts, "You have deleted <b>"+deletedLayers.length+"</b> layer" + ((deletedLayers.length>1)?"s: ":": ") + deletedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", "), "alert-info"); | 237 | $scope.displayAlert($scope.zone2alerts, "You have deleted <b>"+deletedLayers.length+"</b> layer" + ((deletedLayers.length>1)?"s: ":": ") + deletedLayers.map(function (e) { return "<a href=\""+e.layerdetailurl+"\">"+e.name+"</a>" }).join(", "), "alert-info"); |
| 238 | // invalidate error layer data based on current layers | ||
| 239 | $scope.layersForTargets = {}; | ||
| 245 | } | 240 | } |
| 246 | 241 | ||
| 247 | } | 242 | } |
| 243 | |||
| 244 | |||
| 245 | if (_data.builds !== undefined) { | ||
| 246 | var toDelete = []; | ||
| 247 | // step 1 - delete entries not found | ||
| 248 | $scope.builds.forEach(function (elem) { | ||
| 249 | if (-1 == _data.builds.findIndex(function (elemX) { return elemX.id == elem.id && elemX.status == elem.status; })) { | ||
| 250 | toDelete.push(elem); | ||
| 251 | } | ||
| 252 | }); | ||
| 253 | toDelete.forEach(function (elem) { | ||
| 254 | $scope.builds.splice($scope.builds.indexOf(elem),1); | ||
| 255 | }); | ||
| 256 | // step 2 - merge new entries | ||
| 257 | _data.builds.forEach(function (elem) { | ||
| 258 | var found = false; | ||
| 259 | var i = 0; | ||
| 260 | for (i = 0 ; i < $scope.builds.length; i ++) { | ||
| 261 | if ($scope.builds[i].id > elem.id) continue; | ||
| 262 | if ($scope.builds[i].id == elem.id) { found=true; break;} | ||
| 263 | if ($scope.builds[i].id < elem.id) break; | ||
| 264 | } | ||
| 265 | if (!found) { | ||
| 266 | $scope.builds.splice(i, 0, elem); | ||
| 267 | } | ||
| 268 | }); | ||
| 269 | // step 3 - merge "Canceled" builds | ||
| 270 | $scope.canceledBuilds.forEach(function (elem) { | ||
| 271 | // mock the build object | ||
| 272 | var found = false; | ||
| 273 | var i = 0; | ||
| 274 | for (i = 0; i < $scope.builds.length; i ++) { | ||
| 275 | if ($scope.builds[i].id > elem.id) continue; | ||
| 276 | if ($scope.builds[i].id == elem.id) { found=true; break;} | ||
| 277 | if ($scope.builds[i].id < elem.id) break; | ||
| 278 | } | ||
| 279 | if (!found) { | ||
| 280 | $scope.builds.splice(i, 0, elem); | ||
| 281 | } | ||
| 282 | }); | ||
| 283 | |||
| 284 | $scope.fetchLayersForTargets(); | ||
| 285 | } | ||
| 248 | if (_data.targets !== undefined) { | 286 | if (_data.targets !== undefined) { |
| 249 | $scope.targets = _data.targets; | 287 | $scope.targets = _data.targets; |
| 250 | } | 288 | } |
| @@ -267,17 +305,26 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 267 | deffered.resolve(_data); | 305 | deffered.resolve(_data); |
| 268 | } | 306 | } |
| 269 | }).error(function(_data, _status, _headers, _config) { | 307 | }).error(function(_data, _status, _headers, _config) { |
| 270 | console.warn("Failed HTTP XHR request (" + _status + ")" + _data); | 308 | if (_status == 0) { |
| 309 | // the server has gone away | ||
| 310 | alert("The server is not responding. The application will terminate now") | ||
| 311 | $interval.cancel($scope.pollHandle); | ||
| 312 | } | ||
| 313 | else { | ||
| 271 | console.error("Failed HTTP XHR request: ", _data, _status, _headers, _config); | 314 | console.error("Failed HTTP XHR request: ", _data, _status, _headers, _config); |
| 272 | inXHRcall = false; | 315 | inXHRcall = false; |
| 273 | deffered.reject(_data.error); | 316 | deffered.reject(_data.error); |
| 317 | } | ||
| 274 | }); | 318 | }); |
| 275 | 319 | ||
| 276 | return deffered.promise; | 320 | return deffered.promise; |
| 277 | } | 321 | } |
| 278 | 322 | ||
| 279 | $scope.layeralert = undefined; | 323 | $scope.layeralert = undefined; |
| 280 | // shows user alerts on invalid project data | 324 | /** |
| 325 | * Verifies and shows user alerts on invalid project data | ||
| 326 | */ | ||
| 327 | |||
| 281 | $scope.validateData = function () { | 328 | $scope.validateData = function () { |
| 282 | if ($scope.layers.length == 0) { | 329 | if ($scope.layers.length == 0) { |
| 283 | $scope.layeralert = $scope.displayAlert($scope.zone1alerts, "You need to add some layers to this project. <a href=\""+$scope.urls.layers+"\">View all layers available in Toaster</a> or <a href=\""+$scope.urls.importlayer+"\">import a layer</a>"); | 330 | $scope.layeralert = $scope.displayAlert($scope.zone1alerts, "You need to add some layers to this project. <a href=\""+$scope.urls.layers+"\">View all layers available in Toaster</a> or <a href=\""+$scope.urls.importlayer+"\">import a layer</a>"); |
| @@ -289,14 +336,14 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 289 | } | 336 | } |
| 290 | } | 337 | } |
| 291 | 338 | ||
| 292 | $scope.targetExistingBuild = function(targets) { | 339 | $scope.buildExistingTarget = function(targets) { |
| 293 | var oldTargetName = $scope.targetName; | 340 | var oldTargetName = $scope.targetName; |
| 294 | $scope.targetName = targets.map(function(v,i,a){return v.target}).join(' '); | 341 | $scope.targetName = targets.map(function(v,i,a){return v.target}).join(' '); |
| 295 | $scope.targetNamedBuild(); | 342 | $scope.targetNamedBuild(); |
| 296 | $scope.targetName = oldTargetName; | 343 | $scope.targetName = oldTargetName; |
| 297 | } | 344 | } |
| 298 | 345 | ||
| 299 | $scope.targetNamedBuild = function(target) { | 346 | $scope.buildNamedTarget = function(target) { |
| 300 | if ($scope.targetName === undefined && $scope.targetName1 === undefined){ | 347 | if ($scope.targetName === undefined && $scope.targetName1 === undefined){ |
| 301 | console.warn("No target defined, please type in a target name"); | 348 | console.warn("No target defined, please type in a target name"); |
| 302 | return; | 349 | return; |
| @@ -310,7 +357,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 310 | targets: $scope.safeTargetName, | 357 | targets: $scope.safeTargetName, |
| 311 | } | 358 | } |
| 312 | }).then(function (data) { | 359 | }).then(function (data) { |
| 313 | console.warn("received ", data); | 360 | console.warn("TRC3: received ", data); |
| 314 | $scope.targetName = undefined; | 361 | $scope.targetName = undefined; |
| 315 | $scope.targetName1 = undefined; | 362 | $scope.targetName1 = undefined; |
| 316 | $location.hash('buildslist'); | 363 | $location.hash('buildslist'); |
| @@ -329,22 +376,20 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 329 | $scope.safeTargetName = $scope.safeTargetName.replace(/\[.*\]/, '').trim(); | 376 | $scope.safeTargetName = $scope.safeTargetName.replace(/\[.*\]/, '').trim(); |
| 330 | } | 377 | } |
| 331 | 378 | ||
| 332 | $scope.buildCancel = function(id) { | 379 | $scope.buildCancel = function(build) { |
| 333 | $scope._makeXHRCall({ | 380 | $scope._makeXHRCall({ |
| 334 | method: "POST", url: $scope.urls.xhr_build, | 381 | method: "POST", url: $scope.urls.xhr_build, |
| 335 | data: { | 382 | data: { |
| 336 | buildCancel: id, | 383 | buildCancel: build.id, |
| 337 | } | 384 | } |
| 385 | }).then( function () { | ||
| 386 | build['status'] = "deleted"; | ||
| 387 | $scope.canceledBuilds.push(build); | ||
| 338 | }); | 388 | }); |
| 339 | } | 389 | } |
| 340 | 390 | ||
| 341 | $scope.buildDelete = function(id) { | 391 | $scope.buildDelete = function(build) { |
| 342 | $scope._makeXHRCall({ | 392 | $scope.canceledBuilds.splice($scope.canceledBuilds.indexOf(build), 1); |
| 343 | method: "POST", url: $scope.urls.xhr_build, | ||
| 344 | data: { | ||
| 345 | buildDelete: id, | ||
| 346 | } | ||
| 347 | }); | ||
| 348 | } | 393 | } |
| 349 | 394 | ||
| 350 | 395 | ||
| @@ -352,6 +397,12 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 352 | $scope.layerAddId = item.id; | 397 | $scope.layerAddId = item.id; |
| 353 | } | 398 | } |
| 354 | 399 | ||
| 400 | |||
| 401 | $scope.layerAddById = function (id) { | ||
| 402 | $scope.layerAddId = id; | ||
| 403 | $scope.layerAdd(); | ||
| 404 | } | ||
| 405 | |||
| 355 | $scope.layerAdd = function() { | 406 | $scope.layerAdd = function() { |
| 356 | 407 | ||
| 357 | $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "layerdeps", value: $scope.layerAddId }}) | 408 | $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "layerdeps", value: $scope.layerAddId }}) |
| @@ -369,7 +420,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 369 | $scope.selectedItems = (function () { s = {}; for (var i = 0; i < items.length; i++) { s[items[i].id] = true; };return s; })(); | 420 | $scope.selectedItems = (function () { s = {}; for (var i = 0; i < items.length; i++) { s[items[i].id] = true; };return s; })(); |
| 370 | 421 | ||
| 371 | $scope.ok = function() { | 422 | $scope.ok = function() { |
| 372 | console.warn("scope selected is ", $scope.selectedItems); | 423 | console.warn("TRC4: scope selected is ", $scope.selectedItems); |
| 373 | $modalInstance.close(Object.keys($scope.selectedItems).filter(function (e) { return $scope.selectedItems[e];})); | 424 | $modalInstance.close(Object.keys($scope.selectedItems).filter(function (e) { return $scope.selectedItems[e];})); |
| 374 | }; | 425 | }; |
| 375 | 426 | ||
| @@ -378,7 +429,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 378 | }; | 429 | }; |
| 379 | 430 | ||
| 380 | $scope.update = function() { | 431 | $scope.update = function() { |
| 381 | console.warn("updated ", $scope.selectedItems); | 432 | console.warn("TRC5: updated ", $scope.selectedItems); |
| 382 | }; | 433 | }; |
| 383 | }, | 434 | }, |
| 384 | resolve: { | 435 | resolve: { |
| @@ -393,7 +444,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 393 | 444 | ||
| 394 | modalInstance.result.then(function (selectedArray) { | 445 | modalInstance.result.then(function (selectedArray) { |
| 395 | selectedArray.push($scope.layerAddId); | 446 | selectedArray.push($scope.layerAddId); |
| 396 | console.warn("selected", selectedArray); | 447 | console.warn("TRC6: selected", selectedArray); |
| 397 | 448 | ||
| 398 | $scope._makeXHRCall({ | 449 | $scope._makeXHRCall({ |
| 399 | method: "POST", url: $scope.urls.xhr_edit, | 450 | method: "POST", url: $scope.urls.xhr_edit, |
| @@ -429,7 +480,16 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 429 | } | 480 | } |
| 430 | 481 | ||
| 431 | 482 | ||
| 432 | $scope.test = function(elementid) { | 483 | /** |
| 484 | * Verifies if a project settings change would trigger layer updates. If user confirmation is needed, | ||
| 485 | * a modal dialog will prompt the user to ack the changes. If not, the editProjectSettings() function is called directly. | ||
| 486 | * | ||
| 487 | * Only "versionlayers" change for is supported (and hardcoded) for now. | ||
| 488 | */ | ||
| 489 | |||
| 490 | $scope.testProjectSettingsChange = function(elementid) { | ||
| 491 | if (elementid != '#change-project-version') throw "Not implemented"; | ||
| 492 | |||
| 433 | $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "versionlayers", value: $scope.projectVersion }}). | 493 | $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "versionlayers", value: $scope.projectVersion }}). |
| 434 | success(function (_data) { | 494 | success(function (_data) { |
| 435 | if (_data.error != "ok") { | 495 | if (_data.error != "ok") { |
| @@ -463,17 +523,21 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 463 | } | 523 | } |
| 464 | }); | 524 | }); |
| 465 | 525 | ||
| 466 | modalInstance.result.then(function () { $scope.edit(elementid)}); | 526 | modalInstance.result.then(function () { $scope.editProjectSettings(elementid)}); |
| 467 | } else { | 527 | } else { |
| 468 | $scope.edit(elementid); | 528 | $scope.editProjectSettings(elementid); |
| 469 | } | 529 | } |
| 470 | } | 530 | } |
| 471 | }); | 531 | }); |
| 472 | } | 532 | } |
| 473 | 533 | ||
| 474 | $scope.edit = function(elementid) { | 534 | /** |
| 535 | * Performs changes to project settings, and updates the user interface accordingly. | ||
| 536 | */ | ||
| 537 | |||
| 538 | $scope.editProjectSettings = function(elementid) { | ||
| 475 | var data = {}; | 539 | var data = {}; |
| 476 | console.warn("edit with ", elementid); | 540 | console.warn("TRC7: editProjectSettings with ", elementid); |
| 477 | var alertText = undefined; | 541 | var alertText = undefined; |
| 478 | var alertZone = undefined; | 542 | var alertZone = undefined; |
| 479 | var oldLayers = []; | 543 | var oldLayers = []; |
| @@ -508,10 +572,14 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 508 | alertText += "<strong>" + $scope.project.release.desc + "</strong>. "; | 572 | alertText += "<strong>" + $scope.project.release.desc + "</strong>. "; |
| 509 | } | 573 | } |
| 510 | if (elementid == '#change-project-version') { | 574 | if (elementid == '#change-project-version') { |
| 575 | $scope.layersForTargets = {}; // invalidate error layers for the targets, since layers changed | ||
| 576 | |||
| 511 | // requirement https://bugzilla.yoctoproject.org/attachment.cgi?id=2229, notification for changed version to include layers | 577 | // requirement https://bugzilla.yoctoproject.org/attachment.cgi?id=2229, notification for changed version to include layers |
| 512 | $scope.zone2alerts.forEach(function (e) { e.close() }); | 578 | $scope.zone2alerts.forEach(function (e) { e.close() }); |
| 513 | alertText += "This has caused the following changes in your project layers:<ul>" | 579 | alertText += "This has caused the following changes in your project layers:<ul>" |
| 514 | 580 | ||
| 581 | |||
| 582 | // warnings - this is executed AFTER the generic XHRCall handling is done; at this point, | ||
| 515 | if (_data.layers !== undefined) { | 583 | if (_data.layers !== undefined) { |
| 516 | // show added/deleted layer notifications; scope.layers is already updated by this point. | 584 | // show added/deleted layer notifications; scope.layers is already updated by this point. |
| 517 | var addedLayers = []; | 585 | var addedLayers = []; |
| @@ -547,6 +615,10 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 547 | } | 615 | } |
| 548 | 616 | ||
| 549 | 617 | ||
| 618 | /** | ||
| 619 | * Extracts a command passed through the local path in location, and executes/updates UI based on the command | ||
| 620 | */ | ||
| 621 | |||
| 550 | $scope.updateDisplayWithCommands = function() { | 622 | $scope.updateDisplayWithCommands = function() { |
| 551 | cmd = $location.path(); | 623 | cmd = $location.path(); |
| 552 | 624 | ||
| @@ -630,6 +702,10 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 630 | }); | 702 | }); |
| 631 | } | 703 | } |
| 632 | 704 | ||
| 705 | /** | ||
| 706 | * Utility function to display an alert to the user | ||
| 707 | */ | ||
| 708 | |||
| 633 | $scope.displayAlert = function(zone, text, type) { | 709 | $scope.displayAlert = function(zone, text, type) { |
| 634 | if (zone.maxid === undefined) { zone.maxid = 0; } | 710 | if (zone.maxid === undefined) { zone.maxid = 0; } |
| 635 | var crtid = zone.maxid ++; | 711 | var crtid = zone.maxid ++; |
| @@ -644,6 +720,10 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 644 | return o; | 720 | return o; |
| 645 | } | 721 | } |
| 646 | 722 | ||
| 723 | /** | ||
| 724 | * Toggles display items between label and input box (the edit pencil icon) on selected settings in project page | ||
| 725 | */ | ||
| 726 | |||
| 647 | $scope.toggle = function(id) { | 727 | $scope.toggle = function(id) { |
| 648 | $scope.projectName = $scope.project.name; | 728 | $scope.projectName = $scope.project.name; |
| 649 | $scope.projectVersion = $scope.project.release.id; | 729 | $scope.projectVersion = $scope.project.release.id; |
| @@ -657,34 +737,52 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc | |||
| 657 | keys = Object.keys($scope.mostBuiltTargets); | 737 | keys = Object.keys($scope.mostBuiltTargets); |
| 658 | keys = keys.filter(function (e) { if ($scope.mostBuiltTargets[e]) return e }); | 738 | keys = keys.filter(function (e) { if ($scope.mostBuiltTargets[e]) return e }); |
| 659 | return keys.length == 0; | 739 | return keys.length == 0; |
| 740 | } | ||
| 741 | |||
| 742 | /** | ||
| 743 | * Helper function to deal with error string recognition and manipulation | ||
| 744 | */ | ||
| 660 | 745 | ||
| 746 | $scope.getTargetNameFromErrorMsg = function (msg) { | ||
| 747 | targets = msg.split(" ").splice(2).map(function (v) { return v.replace(/'/g, '')}) | ||
| 748 | return targets; | ||
| 661 | } | 749 | } |
| 662 | 750 | ||
| 663 | // init code | 751 | $scope.fetchLayersForTargets = function () { |
| 664 | // | 752 | $scope.builds.forEach(function (buildrequest) { |
| 665 | $scope.init = function() { | 753 | buildrequest.errors.forEach(function (error) { |
| 666 | $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "GET", url: $scope.urls.xhr_edit, data: undefined});}, 2000, 0); | 754 | if (error.msg.indexOf("Nothin") == 0) { |
| 755 | $scope.getTargetNameFromErrorMsg(error.msg).forEach(function (target) { | ||
| 756 | if ($scope.layersForTargets[target] === undefined) | ||
| 757 | $scope.getAutocompleteSuggestions("layers4target", target).then( function (list) { | ||
| 758 | $scope.layersForTargets[target] = list; | ||
| 759 | }) | ||
| 760 | }) | ||
| 761 | } | ||
| 762 | }) | ||
| 763 | }) | ||
| 667 | } | 764 | } |
| 668 | 765 | ||
| 669 | $scope.init(); | ||
| 670 | }); | ||
| 671 | 766 | ||
| 767 | /** | ||
| 768 | * Page init code - just init variables and set the automated refresh | ||
| 769 | */ | ||
| 672 | 770 | ||
| 673 | /** | 771 | $scope.init = function() { |
| 674 | TESTING CODE | 772 | $scope.canceledBuilds = []; |
| 675 | */ | 773 | $scope.layersForTargets = {}; |
| 774 | $scope.fetchLayersForTargets(); | ||
| 775 | $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "GET", url: $scope.urls.xhr_edit, data: undefined});}, 2000, 0); | ||
| 776 | } | ||
| 676 | 777 | ||
| 677 | function test_diff_arrays() { | 778 | }); |
| 678 | _diffArrays([1,2,3], [2,3,4], function(e,f) { return e==f; }, function(e) {console.warn("added", e)}, function(e) {console.warn("deleted", e);}) | ||
| 679 | } | ||
| 680 | 779 | ||
| 681 | // test_diff_arrays(); | ||
| 682 | 780 | ||
| 683 | var s = undefined; | 781 | var s = undefined; |
| 684 | 782 | ||
| 685 | function test_set_alert(text) { | 783 | function test_set_alert(text) { |
| 686 | s = angular.element("div#main").scope(); | 784 | s = angular.element("div#main").scope(); |
| 687 | s.displayAlert(s.zone3alerts, text); | 785 | s.displayAlert(s.zone3alerts, text); |
| 688 | console.warn(s.zone3alerts); | 786 | console.warn("TRC8: zone3alerts", s.zone3alerts); |
| 689 | s.$digest(); | 787 | s.$digest(); |
| 690 | } | 788 | } |
diff --git a/bitbake/lib/toaster/toastergui/templates/project.html b/bitbake/lib/toaster/toastergui/templates/project.html index 2979db74ed..67b267256b 100644 --- a/bitbake/lib/toaster/toastergui/templates/project.html +++ b/bitbake/lib/toaster/toastergui/templates/project.html | |||
| @@ -89,9 +89,9 @@ vim: expandtab tabstop=2 | |||
| 89 | 89 | ||
| 90 | <!-- build form --> | 90 | <!-- build form --> |
| 91 | <div class="well"> | 91 | <div class="well"> |
| 92 | <form class="build-form" ng-submit="targetNamedBuild()"> | 92 | <form class="build-form" ng-submit="buildNamedTarget()"> |
| 93 | <div class="input-append controls"> | 93 | <div class="input-append controls"> |
| 94 | <input type="text" class="huge span7" placeholder="Type the target(s) you want to build" autocomplete="off" ng-model="targetName" typeahead="e.name for e in getSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length"/> | 94 | <input type="text" class="huge span7" placeholder="Type the target(s) you want to build" autocomplete="off" ng-model="targetName" typeahead="e.name for e in getAutocompleteSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length"/> |
| 95 | <button type="submit" id="build-button" class="btn btn-large btn-primary" ng-disabled="!targetName.length"> | 95 | <button type="submit" id="build-button" class="btn btn-large btn-primary" ng-disabled="!targetName.length"> |
| 96 | Build | 96 | Build |
| 97 | </button> | 97 | </button> |
| @@ -108,6 +108,9 @@ vim: expandtab tabstop=2 | |||
| 108 | </form> | 108 | </form> |
| 109 | </div> | 109 | </div> |
| 110 | 110 | ||
| 111 | |||
| 112 | <!-- latest builds list --> | ||
| 113 | |||
| 111 | <a id="buildslist"></a> | 114 | <a id="buildslist"></a> |
| 112 | <h2 class="air" ng-if="builds.length">Latest builds</h2> | 115 | <h2 class="air" ng-if="builds.length">Latest builds</h2> |
| 113 | <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]"> | 116 | <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]"> |
| @@ -116,9 +119,27 @@ vim: expandtab tabstop=2 | |||
| 116 | 119 | ||
| 117 | <case ng-switch-when="failed"> | 120 | <case ng-switch-when="failed"> |
| 118 | <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span></div> | 121 | <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span></div> |
| 122 | <div > | ||
| 123 | <button class="btn pull-right btn-danger" ng-click="buildExistingTarget(b.targets)">Run again</button> | ||
| 124 | </div> | ||
| 119 | <div class="row-fluid"> | 125 | <div class="row-fluid"> |
| 120 | <div class="air well" ng-repeat="e in b.errors"> | 126 | <div class="air well" ng-repeat="e in b.errors"> |
| 121 | Error type {[e.type]}: <pre>{[e.msg]}</pre> | 127 | <pre>{[e.msg]}</pre> |
| 128 | <ngif ng-if="e.msg.indexOf('Nothin') == 0"> | ||
| 129 | <div ng-repeat="t in getTargetNameFromErrorMsg(e.msg)"> | ||
| 130 | <p class="lead">The target <strong>{[t]}</strong> is not provided by any of your project layers.</p> | ||
| 131 | <p> Your build has failed because the target <strong>{[t]}</strong> is not provided by any of your project layers.</p> | ||
| 132 | <ngif ng-if="layersForTargets[t].length > 0"> | ||
| 133 | <p>The following layers provide this target. You could add one of them to your project.</p> | ||
| 134 | <button class="btn btn-danger add-layer-with-dependencies" ng-repeat="l in layersForTargets[t]" ng-click="layerAddById(l.id)">Add {[l.name]}</button> | ||
| 135 | </ngif> | ||
| 136 | </div> | ||
| 137 | </ngif> | ||
| 138 | <ngif ng-if="e.msg.indexOf('Nothin') != 0"> | ||
| 139 | <p> | ||
| 140 | Please contact your system administrator to help troubleshoot this error. | ||
| 141 | </p> | ||
| 142 | </ngif> | ||
| 122 | </div> | 143 | </div> |
| 123 | </div> | 144 | </div> |
| 124 | </case> | 145 | </case> |
| @@ -128,7 +149,7 @@ vim: expandtab tabstop=2 | |||
| 128 | <div class="span4 lead" >Build queued | 149 | <div class="span4 lead" >Build queued |
| 129 | <i title="This build will start as soon as a build server is available" class="icon-question-sign get-help get-help-blue heading-help" data-toggle="tooltip"></i> | 150 | <i title="This build will start as soon as a build server is available" class="icon-question-sign get-help get-help-blue heading-help" data-toggle="tooltip"></i> |
| 130 | </div> | 151 | </div> |
| 131 | <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button> | 152 | <button class="btn pull-right btn-info" ng-click="buildCancel(b)">Cancel</button> |
| 132 | </case> | 153 | </case> |
| 133 | 154 | ||
| 134 | <case ng-switch-when="created"> | 155 | <case ng-switch-when="created"> |
| @@ -136,7 +157,7 @@ vim: expandtab tabstop=2 | |||
| 136 | <div class="span6" > | 157 | <div class="span6" > |
| 137 | <span class="lead">Creating build</span> | 158 | <span class="lead">Creating build</span> |
| 138 | </div> | 159 | </div> |
| 139 | <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button> | 160 | <button class="btn pull-right btn-info" ng-click="buildCancel(b)">Cancel</button> |
| 140 | </case> | 161 | </case> |
| 141 | 162 | ||
| 142 | <case ng-switch-when="deleted"> | 163 | <case ng-switch-when="deleted"> |
| @@ -144,7 +165,7 @@ vim: expandtab tabstop=2 | |||
| 144 | <div class="span6" id="{[b.id]}-deleted" > | 165 | <div class="span6" id="{[b.id]}-deleted" > |
| 145 | <span class="lead">Build deleted</span> | 166 | <span class="lead">Build deleted</span> |
| 146 | </div> | 167 | </div> |
| 147 | <button class="btn pull-right btn-info" ng-click="buildDelete(b.id)">Close</button> | 168 | <button class="btn pull-right btn-info" ng-click="buildDelete(b)">Close</button> |
| 148 | </case> | 169 | </case> |
| 149 | 170 | ||
| 150 | 171 | ||
| @@ -198,7 +219,7 @@ vim: expandtab tabstop=2 | |||
| 198 | </div> | 219 | </div> |
| 199 | <div> <span class="lead">Build time: <a href="{[b.build[0].build_time_page_url]}">{[b.build[0].build_time|timediff]}</a></span> | 220 | <div> <span class="lead">Build time: <a href="{[b.build[0].build_time_page_url]}">{[b.build[0].build_time|timediff]}</a></span> |
| 200 | <button class="btn pull-right" ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]" | 221 | <button class="btn pull-right" ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]" |
| 201 | ng-click="targetExistingBuild(b.targets)">Run again</button> | 222 | ng-click="buildExistingTarget(b.targets)">Run again</button> |
| 202 | 223 | ||
| 203 | </div> | 224 | </div> |
| 204 | </case> | 225 | </case> |
| @@ -244,7 +265,7 @@ vim: expandtab tabstop=2 | |||
| 244 | </div> | 265 | </div> |
| 245 | <form ng-submit="layerAdd()"> | 266 | <form ng-submit="layerAdd()"> |
| 246 | <div class="input-append"> | 267 | <div class="input-append"> |
| 247 | <input type="text" class="input-xlarge" id="layer" autocomplete="off" placeholder="Type a layer name" data-minLength="1" ng-model="layerAddName" typeahead="e.name for e in getSuggestions('layers', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" typeahead-on-select="onLayerSelect($item, $model, $label)" typeahead-editable="false" ng-class="{ 'has-error': layerAddName.$invalid }" /> | 268 | <input type="text" class="input-xlarge" id="layer" autocomplete="off" placeholder="Type a layer name" data-minLength="1" ng-model="layerAddName" typeahead="e.name for e in getAutocompleteSuggestions('layers', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" typeahead-on-select="onLayerSelect($item, $model, $label)" typeahead-editable="false" ng-class="{ 'has-error': layerAddName.$invalid }" /> |
| 248 | <input type="submit" id="add-layer" class="btn" value="Add" ng-disabled="!layerAddName.length"/> | 269 | <input type="submit" id="add-layer" class="btn" value="Add" ng-disabled="!layerAddName.length"/> |
| 249 | </div> | 270 | </div> |
| 250 | {% csrf_token %} | 271 | {% csrf_token %} |
| @@ -265,9 +286,9 @@ vim: expandtab tabstop=2 | |||
| 265 | Targets | 286 | Targets |
| 266 | <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> | 287 | <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> |
| 267 | </h3> | 288 | </h3> |
| 268 | <form ng-submit="targetNamedBuild()"> | 289 | <form ng-submit="buildNamedTarget()"> |
| 269 | <div class="input-append"> | 290 | <div class="input-append"> |
| 270 | <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"> | 291 | <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 getAutocompleteSuggestions('targets', $viewValue)|filter:$viewValue" typeahead-template-url="suggestion_details" ng-disabled="!layers.length"> |
| 271 | <button type="submit" id="build-button" class="btn btn-primary" ng-disabled="!targetName1.length"> | 292 | <button type="submit" id="build-button" class="btn btn-primary" ng-disabled="!targetName1.length"> |
| 272 | Build </button> | 293 | Build </button> |
| 273 | </div> | 294 | </div> |
| @@ -304,8 +325,8 @@ vim: expandtab tabstop=2 | |||
| 304 | <strong>Machine changes have a big impact on build outcome.</strong> | 325 | <strong>Machine changes have a big impact on build outcome.</strong> |
| 305 | You cannot really compare the builds for the new machine with the previous ones. | 326 | You cannot really compare the builds for the new machine with the previous ones. |
| 306 | </div> | 327 | </div> |
| 307 | <form ng-submit="edit('#select-machine')" class="input-append"> | 328 | <form ng-submit="editProjectSettings('#select-machine')" class="input-append"> |
| 308 | <input type="text" id="machine" autocomplete="off" ng-model="machineName" typeahead="m.name for m in getSuggestions('machines', $viewValue)"/> | 329 | <input type="text" id="machine" autocomplete="off" ng-model="machineName" typeahead="m.name for m in getAutocompleteSuggestions('machines', $viewValue)"/> |
| 309 | <input type="submit" id="apply-change-machine" class="btn" type="button" ng-disabled="machineName == machine.name || machineName.length == 0" value="Save"></input> | 330 | <input type="submit" id="apply-change-machine" class="btn" type="button" ng-disabled="machineName == machine.name || machineName.length == 0" value="Save"></input> |
| 310 | <input type="reset" id="cancel-machine" class="btn btn-link" ng-click="toggle('#select-machine')" value="Cancel"></input> | 331 | <input type="reset" id="cancel-machine" class="btn btn-link" ng-click="toggle('#select-machine')" value="Cancel"></input> |
| 311 | {% csrf_token %} | 332 | {% csrf_token %} |
| @@ -337,7 +358,7 @@ vim: expandtab tabstop=2 | |||
| 337 | <i class="icon-pencil" ng-click="toggle('#change-project-name')" ></i> | 358 | <i class="icon-pencil" ng-click="toggle('#change-project-name')" ></i> |
| 338 | </p> | 359 | </p> |
| 339 | <div id="change-project-name" style="display:none;"> | 360 | <div id="change-project-name" style="display:none;"> |
| 340 | <form ng-submit="edit('#change-project-name')" class="input-append"> | 361 | <form ng-submit="editProjectSettings('#change-project-name')" class="input-append"> |
| 341 | <input type="text" class="input-xlarge" id="type-project-name" ng-model="projectName"> | 362 | <input type="text" class="input-xlarge" id="type-project-name" ng-model="projectName"> |
| 342 | <input type="submit" class="btn" value="Save" ng-disabled="project.name == projectName"/> | 363 | <input type="submit" class="btn" value="Save" ng-disabled="project.name == projectName"/> |
| 343 | <input type="reset" class="btn btn-link" value="Cancel" ng-click="toggle('#change-project-name')"> | 364 | <input type="reset" class="btn btn-link" value="Cancel" ng-click="toggle('#change-project-name')"> |
| @@ -354,7 +375,7 @@ vim: expandtab tabstop=2 | |||
| 354 | <i id="change-version" class="icon-pencil" ng-click="toggle('#change-project-version')" ></i> | 375 | <i id="change-version" class="icon-pencil" ng-click="toggle('#change-project-version')" ></i> |
| 355 | </p> | 376 | </p> |
| 356 | <div class="div-inline" id="change-project-version" style="display:none;"> | 377 | <div class="div-inline" id="change-project-version" style="display:none;"> |
| 357 | <form ng-submit="test('#change-project-version')" class="input-append"> | 378 | <form ng-submit="testProjectSettingsChange('#change-project-version')" class="input-append"> |
| 358 | <select id="select-version" ng-model="projectVersion"> | 379 | <select id="select-version" ng-model="projectVersion"> |
| 359 | <option ng-repeat="r in releases" value="{[r.id]}" ng-selected="r.id == project.release.id">{[r.description]}</option> | 380 | <option ng-repeat="r in releases" value="{[r.id]}" ng-selected="r.id == project.release.id">{[r.description]}</option> |
| 360 | </select> | 381 | </select> |
| @@ -404,6 +425,7 @@ angular.element(document).ready(function() { | |||
| 404 | scope.updateDisplayWithCommands(); | 425 | scope.updateDisplayWithCommands(); |
| 405 | scope.validateData(); | 426 | scope.validateData(); |
| 406 | 427 | ||
| 428 | scope.init(); | ||
| 407 | scope.$digest(); | 429 | scope.$digest(); |
| 408 | 430 | ||
| 409 | }); | 431 | }); |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 420b37cb73..8c21ca48e0 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -40,7 +40,6 @@ from django.utils import formats | |||
| 40 | from toastergui.templatetags.projecttags import json as jsonfilter | 40 | from toastergui.templatetags.projecttags import json as jsonfilter |
| 41 | import json | 41 | import json |
| 42 | 42 | ||
| 43 | |||
| 44 | # all new sessions should come through the landing page; | 43 | # all new sessions should come through the landing page; |
| 45 | # determine in which mode we are running in, and redirect appropriately | 44 | # determine in which mode we are running in, and redirect appropriately |
| 46 | def landing(request): | 45 | def landing(request): |
| @@ -52,37 +51,25 @@ def landing(request): | |||
| 52 | 51 | ||
| 53 | return render(request, 'landing.html') | 52 | return render(request, 'landing.html') |
| 54 | 53 | ||
| 54 | # returns a list for most recent builds; for use in the Project page, xhr_ updates, and other places, as needed | ||
| 55 | def _project_recent_build_list(prj): | 55 | def _project_recent_build_list(prj): |
| 56 | # build requests not yet started | 56 | return map(lambda x: { |
| 57 | return (map(lambda x: { | 57 | "id": x.pk, |
| 58 | "id": x.pk, | 58 | "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.brtarget_set.all()), |
| 59 | "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()), | 59 | "status": x.get_state_display(), |
| 60 | "status": x.get_state_display(), | 60 | "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.exclude(errmsg__contains="Command Failed")), |
| 61 | }, prj.buildrequest_set.filter(state__lt = BuildRequest.REQ_INPROGRESS).order_by("-pk")) + | 61 | "build" : map( lambda y: {"id": y.pk, |
| 62 | # build requests started, but with no build yet | 62 | "status": y.get_outcome_display(), |
| 63 | map(lambda x: { | 63 | "completed_on" : y.completed_on.strftime('%s')+"000", |
| 64 | "id": x.pk, | 64 | "build_time" : (y.completed_on - y.started_on).total_seconds(), |
| 65 | "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()), | 65 | "build_page_url" : reverse('builddashboard', args=(y.pk,)), |
| 66 | "status": x.get_state_display(), | 66 | 'build_time_page_url': reverse('buildtime', args=(y.pk,)), |
| 67 | }, prj.buildrequest_set.filter(state = BuildRequest.REQ_INPROGRESS, build = None).order_by("-pk")) + | 67 | "errors": y.errors_no, |
| 68 | # build requests that failed | 68 | "warnings": y.warnings_no, |
| 69 | map(lambda x: { | 69 | "completeper": y.completeper(), |
| 70 | "id": x.pk, | 70 | "eta": y.eta().strftime('%s')+"000"}, Build.objects.filter(buildrequest = x)), |
| 71 | "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()), | 71 | }, list(prj.buildrequest_set.filter(Q(state__lt=BuildRequest.REQ_COMPLETED) or Q(state=BuildRequest.REQ_DELETED)).order_by("-pk")) + |
| 72 | "status": x.get_state_display(), | 72 | list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3])) |
| 73 | "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()), | ||
| 74 | }, prj.buildrequest_set.filter(state = BuildRequest.REQ_FAILED).order_by("-pk")) + | ||
| 75 | # and already made builds | ||
| 76 | map(lambda x: { | ||
| 77 | "id": x.pk, | ||
| 78 | "targets": map(lambda y: {"target": y.target }, x.target_set.all()), | ||
| 79 | "status": x.get_outcome_display(), | ||
| 80 | "completed_on" : x.completed_on.strftime('%s')+"000", | ||
| 81 | "build_time" : (x.completed_on - x.started_on).total_seconds(), | ||
| 82 | "build_page_url" : reverse('builddashboard', args=(x.pk,)), | ||
| 83 | "completeper": x.completeper(), | ||
| 84 | "eta": x.eta().ctime(), | ||
| 85 | }, prj.build_set.all())) | ||
| 86 | 73 | ||
| 87 | 74 | ||
| 88 | def _build_page_range(paginator, index = 1): | 75 | def _build_page_range(paginator, index = 1): |
| @@ -1959,25 +1946,6 @@ if toastermain.settings.MANAGED: | |||
| 1959 | 1946 | ||
| 1960 | raise Exception("Invalid HTTP method for this page") | 1947 | raise Exception("Invalid HTTP method for this page") |
| 1961 | 1948 | ||
| 1962 | # returns a list for most recent builds; for use in the Project page, xhr_ updates, and other places, as needed | ||
| 1963 | def _project_recent_build_list(prj): | ||
| 1964 | return map(lambda x: { | ||
| 1965 | "id": x.pk, | ||
| 1966 | "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.brtarget_set.all()), | ||
| 1967 | "status": x.get_state_display(), | ||
| 1968 | "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()), | ||
| 1969 | "build" : map( lambda y: {"id": y.pk, | ||
| 1970 | "status": y.get_outcome_display(), | ||
| 1971 | "completed_on" : y.completed_on.strftime('%s')+"000", | ||
| 1972 | "build_time" : (y.completed_on - y.started_on).total_seconds(), | ||
| 1973 | "build_page_url" : reverse('builddashboard', args=(y.pk,)), | ||
| 1974 | 'build_time_page_url': reverse('buildtime', args=(y.pk,)), | ||
| 1975 | "errors": y.errors_no, | ||
| 1976 | "warnings": y.warnings_no, | ||
| 1977 | "completeper": y.completeper(), | ||
| 1978 | "eta": y.eta().strftime('%s')+"000"}, Build.objects.filter(buildrequest = x)), | ||
| 1979 | }, list(prj.buildrequest_set.filter(Q(state__lt=BuildRequest.REQ_COMPLETED) or Q(state=BuildRequest.REQ_DELETED)).order_by("-pk")) + | ||
| 1980 | list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3])) | ||
| 1981 | 1949 | ||
| 1982 | 1950 | ||
| 1983 | # Shows the edit project page | 1951 | # Shows the edit project page |
| @@ -2177,7 +2145,7 @@ if toastermain.settings.MANAGED: | |||
| 2177 | # all layers for the current project | 2145 | # all layers for the current project |
| 2178 | queryset_all = prj.compatible_layerversions().filter(layer__name__icontains=request.GET.get('value','')) | 2146 | queryset_all = prj.compatible_layerversions().filter(layer__name__icontains=request.GET.get('value','')) |
| 2179 | 2147 | ||
| 2180 | # but not layers with equivalent layers already in project | 2148 | # but not layers with equivalent layers already in project |
| 2181 | if not request.GET.has_key('include_added'): | 2149 | if not request.GET.has_key('include_added'): |
| 2182 | queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()])[:8] | 2150 | queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()])[:8] |
| 2183 | 2151 | ||
| @@ -2192,7 +2160,9 @@ if toastermain.settings.MANAGED: | |||
| 2192 | queryset = prj.compatible_layerversions().exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]).filter( | 2160 | queryset = prj.compatible_layerversions().exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]).filter( |
| 2193 | layer__name__in = [ x.depends_on.layer.name for x in LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])]) | 2161 | layer__name__in = [ x.depends_on.layer.name for x in LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])]) |
| 2194 | 2162 | ||
| 2195 | return HttpResponse(jsonfilter( { "error":"ok", "list" : map( _lv_to_dict, queryset) }), content_type = "application/json") | 2163 | final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset]) |
| 2164 | |||
| 2165 | return HttpResponse(jsonfilter( { "error":"ok", "list" : map( _lv_to_dict, final_list) }), content_type = "application/json") | ||
| 2196 | 2166 | ||
| 2197 | 2167 | ||
| 2198 | 2168 | ||
| @@ -2213,16 +2183,36 @@ if toastermain.settings.MANAGED: | |||
| 2213 | }), content_type = "application/json") | 2183 | }), content_type = "application/json") |
| 2214 | 2184 | ||
| 2215 | 2185 | ||
| 2186 | # returns layer versions that provide the named targets | ||
| 2187 | if request.GET['type'] == "layers4target": | ||
| 2188 | # we returnd ata only if the recipe can't be provided by the current project layer set | ||
| 2189 | if reduce(lambda x, y: x + y, [x.recipe_layer_version.filter(name="anki").count() for x in prj.projectlayer_equivalent_set()], 0): | ||
| 2190 | final_list = [] | ||
| 2191 | else: | ||
| 2192 | queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET.get('value', '__none__')) | ||
| 2193 | |||
| 2194 | # exclude layers in the project | ||
| 2195 | queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]) | ||
| 2196 | |||
| 2197 | # and show only the selected layers for this project | ||
| 2198 | final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset_all]) | ||
| 2199 | |||
| 2200 | return HttpResponse(jsonfilter( { "error":"ok", "list" : map( _lv_to_dict, final_list) }), content_type = "application/json") | ||
| 2201 | |||
| 2216 | # returns targets provided by current project layers | 2202 | # returns targets provided by current project layers |
| 2217 | if request.GET['type'] == "targets": | 2203 | if request.GET['type'] == "targets": |
| 2218 | queryset_all = Recipe.objects.all() | 2204 | queryset_all = Recipe.objects.all() |
| 2219 | queryset_all = queryset_all.filter(layer_version__in = prj.projectlayer_equivalent_set()) | 2205 | layer_equivalent_set = [] |
| 2206 | for i in prj.projectlayer_set.all(): | ||
| 2207 | layer_equivalent_set += i.layercommit.get_equivalents_wpriority(prj) | ||
| 2208 | queryset_all = queryset_all.filter(layer_version__in = layer_equivalent_set) | ||
| 2220 | return HttpResponse(jsonfilter({ "error":"ok", | 2209 | return HttpResponse(jsonfilter({ "error":"ok", |
| 2221 | "list" : map ( lambda x: {"id": x.pk, "name": x.name, "detail":"[" + x.layer_version.layer.name+ (" | " + x.layer_version.up_branch.name + "]" if x.layer_version.up_branch is not None else "]")}, | 2210 | "list" : map ( lambda x: {"id": x.pk, "name": x.name, "detail":"[" + x.layer_version.layer.name+ (" | " + x.layer_version.up_branch.name + "]" if x.layer_version.up_branch is not None else "]")}, |
| 2222 | queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]), | 2211 | queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]), |
| 2223 | 2212 | ||
| 2224 | }), content_type = "application/json") | 2213 | }), content_type = "application/json") |
| 2225 | 2214 | ||
| 2215 | # returns machines provided by the current project layers | ||
| 2226 | if request.GET['type'] == "machines": | 2216 | if request.GET['type'] == "machines": |
| 2227 | queryset_all = Machine.objects.all() | 2217 | queryset_all = Machine.objects.all() |
| 2228 | if 'project_id' in request.session: | 2218 | if 'project_id' in request.session: |
| @@ -2234,6 +2224,7 @@ if toastermain.settings.MANAGED: | |||
| 2234 | 2224 | ||
| 2235 | }), content_type = "application/json") | 2225 | }), content_type = "application/json") |
| 2236 | 2226 | ||
| 2227 | # returns all projects | ||
| 2237 | if request.GET['type'] == "projects": | 2228 | if request.GET['type'] == "projects": |
| 2238 | queryset_all = Project.objects.all() | 2229 | queryset_all = Project.objects.all() |
| 2239 | ret = { "error": "ok", | 2230 | ret = { "error": "ok", |
