summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui/static/js/projectapp.js
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/toastergui/static/js/projectapp.js')
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projectapp.js234
1 files changed, 166 insertions, 68 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
105if (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
104var projectApp = angular.module('project', ['ngCookies', 'ngAnimate', 'ui.bootstrap', 'ngRoute', 'ngSanitize'], angular_formpost); 114var 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
131projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $cookieStore, $q, $sce, $anchorScroll, $animate, $sanitize) { 143projectApp.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
677function 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
683var s = undefined; 781var s = undefined;
684 782
685function test_set_alert(text) { 783function 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}