summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui/static
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2014-09-09 11:47:13 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-10-30 13:39:49 +0000
commit960580cb70ab1c775b49f8a40d41632c080b3cbb (patch)
tree173570e0a9a80b14926c9dbbac995a39c49fbdcb /bitbake/lib/toaster/toastergui/static
parent1a463ab98ec1220b22a721a1f88ff5af61c33dc3 (diff)
downloadpoky-960580cb70ab1c775b49f8a40d41632c080b3cbb.tar.gz
bitbake: toaster: fix Project page in order to trigger builds
This patch rewrites the Project page and the additional infrastructure in order to fix a bug that makes triggering builds through UI impossible, and to introduce data feeds for suggestions for the user. Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastergui/static')
-rw-r--r--bitbake/lib/toaster/toastergui/static/css/default.css60
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projectapp.js531
2 files changed, 584 insertions, 7 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/css/default.css b/bitbake/lib/toaster/toastergui/static/css/default.css
index 8e0df591df..8780c4f23d 100644
--- a/bitbake/lib/toaster/toastergui/static/css/default.css
+++ b/bitbake/lib/toaster/toastergui/static/css/default.css
@@ -8,10 +8,14 @@
8 8
9/* Styles for the help information */ 9/* Styles for the help information */
10.get-help { color: #CCCCCC; } 10.get-help { color: #CCCCCC; }
11.get-help:hover { color: #999999; cursor: pointer; } 11.get-help:hover, .icon-plus-sign:hover { color: #999999; cursor: pointer; }
12.get-help-blue { color: #3A87AD; } 12.get-help-blue { color: #3A87AD; }
13.get-help-blue:hover { color: #005580; cursor: pointer; } 13.get-help-blue:hover { color: #005580; cursor: pointer; }
14.manual { margin-top: 11px; } 14.get-help-yellow { color: #C09853; }
15.get-help-yellow:hover { color: #B38942; cursor: pointer; }
16.get-help-red { color: #B94A48; font-size: 16px; padding-left: 2px; }
17.get-help-red:hover { color: #943A38; cursor: pointer; }
18.manual { margin: 11px 15px;}
15.heading-help { font-size: 14px; } 19.heading-help { font-size: 14px; }
16 20
17/* Styles for the external link */ 21/* Styles for the external link */
@@ -44,6 +48,7 @@ dd p { line-height: 20px; }
44 48
45/* Some extra space before headings when needed */ 49/* Some extra space before headings when needed */
46.details { margin-top: 30px; } 50.details { margin-top: 30px; }
51.air { margin-top: 30px; }
47 52
48/* Required classes for the highlight behaviour in tables */ 53/* Required classes for the highlight behaviour in tables */
49.highlight { -webkit-animation: target-fade 10s 1; -moz-animation: target-fade 10s 1; animation: target-fade 10s 1; } 54.highlight { -webkit-animation: target-fade 10s 1; -moz-animation: target-fade 10s 1; animation: target-fade 10s 1; }
@@ -96,6 +101,10 @@ th > a, th > span { font-weight: normal; }
96.content-directory a:hover { color: #005580; text-decoration: underline; } 101.content-directory a:hover { color: #005580; text-decoration: underline; }
97.symlink { color: #CCCCCC; } 102.symlink { color: #CCCCCC; }
98 103
104/* Styles for the navbar actions */
105.btn-group + .btn-group { margin-right: 10px; }
106.navbar-inner > .btn-group { margin-top: 6px; }
107
99/* Other styles */ 108/* Other styles */
100.dropdown-menu { padding: 10px; } 109.dropdown-menu { padding: 10px; }
101select { width: auto; } 110select { width: auto; }
@@ -104,6 +113,7 @@ select { width: auto; }
104.progress { margin-bottom: 0px; } 113.progress { margin-bottom: 0px; }
105.lead .badge { font-size: 18px; font-weight: normal; border-radius: 15px; padding: 9px; } 114.lead .badge { font-size: 18px; font-weight: normal; border-radius: 15px; padding: 9px; }
106.well > .lead, .alert .lead { margin-bottom: 0px; } 115.well > .lead, .alert .lead { margin-bottom: 0px; }
116.well-transparent { background-color: transparent; }
107.no-results { margin: 10px 0; } 117.no-results { margin: 10px 0; }
108.task-name { margin-left: 7px; } 118.task-name { margin-left: 7px; }
109.icon-hand-right {color: #CCCCCC; } 119.icon-hand-right {color: #CCCCCC; }
@@ -119,9 +129,14 @@ select { width: auto; }
119/* Configuration styles */ 129/* Configuration styles */
120.icon-trash { color: #B94A48; font-size: 16px; padding-left: 2px; } 130.icon-trash { color: #B94A48; font-size: 16px; padding-left: 2px; }
121.icon-trash:hover { color: #943A38; text-decoration: none; cursor: pointer; } 131.icon-trash:hover { color: #943A38; text-decoration: none; cursor: pointer; }
122.icon-pencil, .icon-download-alt { font-size: 16px; color: #0088CC; padding-left: 2px; } 132.icon-pencil, .icon-download-alt, .icon-refresh, .icon-star-empty, .icon-star, .icon-tasks { font-size: 16px; color: #0088CC; padding-left: 2px; }
123.icon-pencil:hover, .icon-download-alt:hover { color: #005580; text-decoration: none; cursor: pointer; } 133.icon-pencil:hover, .icon-download-alt:hover, .icon-refresh:hover, .icon-star-empty:hover, .icon-star:hover, .icon-tasks:hover { color: #005580; text-decoration: none; cursor: pointer; }
124.configuration-list li { line-height: 35px; font-size: 21px; font-weight: 200; } 134.icon-share { padding-left: 2px; }
135.alert-success .icon-refresh, .alert-success .icon-tasks { color: #468847; }
136.alert-success .icon-refresh:hover, .alert-success .icon-tasks:hover { color: #347132; }
137.alert-error .icon-refresh, .alert-error .icon-tasks { color: #b94a48; }
138.alert-error .icon-refresh:hover, .alert-error .icon-tasks:hover { color: #943A38; }
139.configuration-list li, .configuration-list label { line-height: 35px; font-size: 21px; font-weight: 200; margin-bottom: 0px;}
125.configuration-list { font-size: 16px; margin-bottom: 1.5em; } 140.configuration-list { font-size: 16px; margin-bottom: 1.5em; }
126.configuration-list i { font-size: 16px; } 141.configuration-list i { font-size: 16px; }
127/*.configuration-layers { height: 135px; overflow: scroll; }*/ 142/*.configuration-layers { height: 135px; overflow: scroll; }*/
@@ -132,15 +147,46 @@ select { width: auto; }
132.configuration-alert p { margin-bottom: 0px; } 147.configuration-alert p { margin-bottom: 0px; }
133fieldset { padding-left: 19px; } 148fieldset { padding-left: 19px; }
134.project-form { margin-top: 10px; } 149.project-form { margin-top: 10px; }
135.add-layers .btn-block + .btn-block { margin-top: 0px; } 150.add-layers .btn-block + .btn-block, .build .btn-block + .btn-block { margin-top: 0px; }
136input.huge { font-size: 17.5px; padding: 11px 19px; } 151input.huge { font-size: 17.5px; padding: 11px 19px; }
137.build-form { margin-bottom: 0px; padding-left: 20px; } 152.build-form { margin-bottom: 0px; }
153.build-form .input-append { margin-bottom: 0px; }
154.build-form .btn-large { padding: 11px 35px; }
155.build-form p { font-size:17.5px ;margin:12px 0 0 10px;}
156.btn-primary .icon-question-sign, .btn-danger .icon-question-sign { color: #fff; }
157.btn-primary .icon-question-sign:hover, .btn-danger .icon-question-sign:hover { color: #999; }
138a code { color: #0088CC; } 158a code { color: #0088CC; }
139a code:hover { color: #005580; } 159a code:hover { color: #005580; }
140.localconf { font-size: 17.5px; margin-top: 40px; } 160.localconf { font-size: 17.5px; margin-top: 40px; }
141.localconf code { font-size: 17.5px; } 161.localconf code { font-size: 17.5px; }
142#add-layer-dependencies { margin-top: 5px; } 162#add-layer-dependencies { margin-top: 5px; }
163.link-action { font-size: 17.5px; margin-top: 40px; }
164.link-action code { font-size: 17.5px; }
143.artifact { width: 9em; } 165.artifact { width: 9em; }
144.control-group { margin-bottom: 0px; } 166.control-group { margin-bottom: 0px; }
145#project-details form { margin: 0px; } 167#project-details form { margin: 0px; }
146dd form { margin: 10px 0 0 0; } 168dd form { margin: 10px 0 0 0; }
169dd form { margin-bottom: 0px; }
170dl textarea { resize: vertical; }
171.navbar-fixed-top { z-index: 1; }
172.popover { z-index: 2; }
173.btn-danger .icon-trash { color: #fff; }
174.bbappends { list-style-type: none; margin-left: 0; }
175.bbappends li { line-height: 25px; }
176.configuration-list input[type="checkbox"] { margin-top:13px;margin-right:10px; }
177.alert input[type="checkbox"] { margin-top: 0px; margin-right: 3px; }
178.alert ol { padding: 10px 0px 0px 20px; }
179.alert ol > li { line-height: 35px; }
180.dl-vertical form { margin-top: 10px; }
181.scrolling { border: 1px solid #dddddd; height: 154px; overflow: auto; padding: 8px; width: 27.5%; margin-bottom: 10px; }
182.lead .help-block { font-size: 14px; line-height: 20px; font-weight: normal; }
183.button-place .btn { margin: 0 0 20px 0; }
184.tooltip-inner { max-width: 250px; }
185dd > span { line-height: 20px; }
186.new-build { padding: 20px; }
187.new-build li { line-height: 30px; }
188.new-build h6 { margin: 10px 0 0 0; color: #5a5a5a; }
189.new-build h3 { margin: 0; color: #5a5a5a; }
190.new-build form { margin: 5px 0 0; }
191.new-build .input-append { margin-bottom: 0; }
192#build-selected { margin-top: 15px; }
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectapp.js b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
new file mode 100644
index 0000000000..e674d8ffd1
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
@@ -0,0 +1,531 @@
1// vim: set tabstop=4 expandtab ai:
2// BitBake Toaster Implementation
3//
4// Copyright (C) 2013 Intel Corporation
5//
6// This program is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License version 2 as
8// published by the Free Software Foundation.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License along
16// with this program; if not, write to the Free Software Foundation, Inc.,
17// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19angular_formpost = function($httpProvider) {
20 // Use x-www-form-urlencoded Content-Type
21 // By Ezekiel Victor, http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/, no license, with attribution
22 $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
23
24 /**
25 * The workhorse; converts an object to x-www-form-urlencoded serialization.
26 * @param {Object} obj
27 * @return {String}
28 */
29 var param = function(obj) {
30 var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
31
32 for(name in obj) {
33 value = obj[name];
34
35 if(value instanceof Array) {
36 for(i=0; i<value.length; ++i) {
37 subValue = value[i];
38 fullSubName = name + '[' + i + ']';
39 innerObj = {};
40 innerObj[fullSubName] = subValue;
41 query += param(innerObj) + '&';
42 }
43 }
44 else if(value instanceof Object) {
45 for(subName in value) {
46 subValue = value[subName];
47 fullSubName = name + '[' + subName + ']';
48 innerObj = {};
49 innerObj[fullSubName] = subValue;
50 query += param(innerObj) + '&';
51 }
52 }
53 else if(value !== undefined && value !== null)
54 query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
55 }
56
57 return query.length ? query.substr(0, query.length - 1) : query;
58 };
59
60 // Override $http service's default transformRequest
61 $httpProvider.defaults.transformRequest = [function(data) {
62 return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
63 }];
64}
65
66
67/**
68 * Helper to execute callback on elements from array differences; useful for incremental UI updating.
69 * @param {Array} oldArray
70 * @param {Array} newArray
71 * @param {function} compareElements
72 * @param {function} onAdded
73 * @param {function} onDeleted
74 *
75 * no return
76 */
77function _diffArrays(oldArray, newArray, compareElements, onAdded, onDeleted ) {
78 if (onDeleted !== undefined) {
79 oldArray.filter(function (e) { var found = 0; newArray.map(function (f) { if (compareElements(e, f)) {found = 1};}); return !found;}).map(onDeleted);
80 }
81 if (onAdded !== undefined) {
82 newArray.filter(function (e) { var found = 0; oldArray.map(function (f) { if (compareElements(e, f)) {found = 1};}); return !found;}).map(onAdded);
83 }
84}
85
86
87var projectApp = angular.module('project', ['ui.bootstrap', 'ngCookies'], angular_formpost);
88
89// modify the template tag markers to prevent conflicts with Django
90projectApp.config(function($interpolateProvider) {
91 $interpolateProvider.startSymbol("{[");
92 $interpolateProvider.endSymbol("]}");
93});
94
95// main controller for the project page
96projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $q, $sce) {
97
98 $scope.getSuggestions = function(type, currentValue) {
99 var deffered = $q.defer();
100
101 $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: type, value: currentValue}})
102 .success(function (_data) {
103 if (_data.error != "ok") {
104 alert(_data.error);
105 deffered.reject(_data.error);
106 }
107 deffered.resolve(_data.list);
108 });
109
110 return deffered.promise;
111 }
112
113 var inXHRcall = false;
114
115 // default handling of XHR calls that handles errors and updates commonly-used pages
116 $scope._makeXHRCall = function(callparams) {
117 if (inXHRcall) {
118 if (callparams.data === undefined) {
119 // we simply skip the data refresh calls
120 console.log("race on XHR, aborted");
121 return;
122 } else {
123 // we return a promise that we'll solve by reissuing the command later
124 var delayed = $q.defer();
125 console.log("race on XHR, delayed");
126 $interval(function () {$scope._makeXHRCall(callparams).then(function (d) { delayed.resolve(d); });}, 100, 1);
127
128 return delayed.promise;
129 }
130
131 }
132 var deffered = $q.defer();
133
134 if (undefined === callparams.headers) { callparams.headers = {} };
135 callparams.headers['X-CSRFToken'] = $cookies.csrftoken;
136
137 $http(callparams).success(function(_data, _status, _headers, _config) {
138 if (_data.error != "ok") {
139 alert("Failed XHR request (" + _status + "): " + _data.error);
140 console.error("Failed XHR request: ", _data, _status, _headers, _config);
141 deffered.reject(_data.error);
142 }
143 else {
144 // TODO: update screen data if we have fields here
145
146 if (_data.builds !== undefined) {
147
148 var oldbuilds = $scope.builds;
149 $scope.builds = _data.builds;
150
151 // identify canceled builds here, so we can display them.
152 _diffArrays(oldbuilds, $scope.builds,
153 function (e,f) { return e.status == f.status && e.id == f.id }, // compare
154 undefined, // added
155 function (e) { // deleted
156 if (e.status == "deleted") return;
157 e.status = "deleted";
158 for (var i = 0; i < $scope.builds.length; i++) {
159 if ($scope.builds[i].status == "queued" && $scope.builds[i].id > e.id)
160 continue;
161 $scope.builds.splice(i, 0, e);
162 break;
163 }
164 });
165
166 }
167 if (_data.layers !== undefined) {
168 var oldlayers = $scope.layers;
169 $scope.layers = _data.layers;
170
171 // show added/deleted layer notifications
172 var addedLayers = [];
173 var deletedLayers = [];
174 _diffArrays( oldlayers, $scope.layers, function (e, f) { return e.id == f.id },
175 function (e) { console.log("new layer", e);addedLayers.push(e); },
176 function (e) { console.log("del layer", e);deletedLayers.push(e); });
177
178 if (addedLayers.length > 0) {
179 $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");
180 }
181 if (deletedLayers.length > 0) {
182 $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");
183 }
184
185 }
186 if (_data.targets !== undefined) {
187 $scope.targets = _data.targets;
188 }
189 if (_data.machine !== undefined) {
190 $scope.machine = _data.machine;
191 }
192 if (_data.user !== undefined) {
193 $scope.user = _data.user;
194 }
195
196 if (_data.prj !== undefined) {
197 $scope.project = _data.prj;
198
199 // update breadcrumb, outside the controller
200 $('#project_name').text($scope.project.name);
201 }
202
203 $scope.validateData();
204 inXHRcall = false;
205 deffered.resolve(_data);
206 }
207 }).error(function(_data, _status, _headers, _config) {
208 alert("Failed HTTP XHR request (" + _status + ")" + _data);
209 console.error("Failed HTTP XHR request: ", _data, _status, _headers, _config);
210 inXHRcall = false;
211 deffered.reject(_data.error);
212 });
213
214 return deffered.promise;
215 }
216
217 $scope.layeralert = undefined;
218 // shows user alerts on invalid project data
219 $scope.validateData = function () {
220 if ($scope.layers.length == 0) {
221 $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>");
222 } else {
223 if ($scope.layeralert != undefined) {
224 $scope.layeralert.close();
225 $scope.layeralert = undefined;
226 }
227 }
228 }
229
230 $scope.targetExistingBuild = function(targets) {
231 var oldTargetName = $scope.targetName;
232 $scope.targetName = targets.map(function(v,i,a){return v.target}).join(' ');
233 $scope.targetNamedBuild();
234 $scope.targetName = oldTargetName;
235 }
236
237 $scope.targetNamedBuild = function(target) {
238 if ($scope.targetName === undefined){
239 alert("No target defined, please type in a target name");
240 return;
241 }
242
243 $scope.sanitizeTargetName();
244
245 $scope._makeXHRCall({
246 method: "POST", url: $scope.urls.xhr_build,
247 data : {
248 targets: $scope.targetName
249 }
250 }).then(function (data) {
251 console.log("received ", data);
252 $scope.targetName = undefined;
253 });
254 }
255
256 $scope.sanitizeTargetName = function() {
257 if (undefined === $scope.targetName) return;
258 $scope.targetName = $scope.targetName.replace(/\[.*\]/, '').trim();
259 }
260
261 $scope.buildCancel = function(id) {
262 $scope._makeXHRCall({
263 method: "POST", url: $scope.urls.xhr_build,
264 data: {
265 buildCancel: id,
266 }
267 });
268 }
269
270 $scope.onLayerSelect = function (item, model, label) {
271 $scope.layerAddId = item.id;
272 }
273
274 $scope.layerAdd = function() {
275
276 $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "layerdeps", value: $scope.layerAddId }})
277 .success(function (_data) {
278 if (_data.error != "ok") {
279 alert(_data.error);
280 } else {
281 if (_data.list.length > 0) {
282 // activate modal
283 var modalInstance = $modal.open({
284 templateUrl: 'dependencies_modal',
285 controller: function ($scope, $modalInstance, items, layerAddName) {
286 $scope.items = items;
287 $scope.layerAddName = layerAddName;
288 $scope.selectedItems = (function () { s = {}; for (var i = 0; i < items.length; i++) { s[items[i].id] = true; };return s; })();
289
290 $scope.ok = function() {
291 console.log("scope selected is ", $scope.selectedItems);
292 $modalInstance.close(Object.keys($scope.selectedItems).filter(function (e) { return $scope.selectedItems[e];}));
293 };
294
295 $scope.cancel = function() {
296 $modalInstance.dismiss('cancel');
297 };
298
299 $scope.update = function() {
300 console.log("updated ", $scope.selectedItems);
301 };
302 },
303 resolve: {
304 items: function () {
305 return _data.list;
306 },
307 layerAddName: function () {
308 return $scope.layerAddName;
309 },
310 }
311 });
312
313 modalInstance.result.then(function (selectedArray) {
314 selectedArray.push($scope.layerAddId);
315 console.log("selected", selectedArray);
316
317 $scope._makeXHRCall({
318 method: "POST", url: $scope.urls.xhr_edit,
319 data: {
320 layerAdd: selectedArray.join(","),
321 }
322 }).then(function () {
323 $scope.layerAddName = undefined;
324 });
325 });
326 }
327 else {
328 $scope._makeXHRCall({
329 method: "POST", url: $scope.urls.xhr_edit,
330 data: {
331 layerAdd: $scope.layerAddId,
332 }
333 }).then(function () {
334 $scope.layerAddName = undefined;
335 });
336 }
337 }
338 });
339 }
340
341 $scope.layerDel = function(id) {
342 $scope._makeXHRCall({
343 method: "POST", url: $scope.urls.xhr_edit,
344 data: {
345 layerDel: id,
346 }
347 });
348 }
349
350
351 $scope.test = function(elementid) {
352 $http({method:"GET", url: $scope.urls.xhr_datatypeahead, params : { type: "versionlayers", value: $scope.projectVersion }}).
353 success(function (_data) {
354 if (_data.error != "ok") {
355 alert (_data.error);
356 }
357 else {
358 if (_data.list.length > 0) {
359 // activate modal
360 var modalInstance = $modal.open({
361 templateUrl: 'change_version_modal',
362 controller: function ($scope, $modalInstance, items, releaseName) {
363 $scope.items = items;
364 $scope.releaseName = releaseName;
365
366 $scope.ok = function() {
367 $modalInstance.close();
368 };
369
370 $scope.cancel = function() {
371 $modalInstance.dismiss('cancel');
372 };
373
374 },
375 resolve: {
376 items: function () {
377 return _data.list;
378 },
379 releaseName: function () {
380 return $scope.releases.filter(function (e) { if (e.id == $scope.projectVersion) return e;})[0].name;
381 },
382 }
383 });
384
385 modalInstance.result.then(function () { $scope.edit(elementid)});
386 } else {
387 $scope.edit(elementid);
388 }
389 }
390 });
391 }
392
393 $scope.edit = function(elementid) {
394 var data = {};
395 console.log("edit with ", elementid);
396 var alertText = undefined;
397 var alertZone = undefined;
398 switch(elementid) {
399 case '#select-machine':
400 alertText = "You have changed the machine to: <b>" + $scope.machineName + "</b>";
401 alertZone = $scope.zone2alerts;
402 data['machineName'] = $scope.machineName;
403 break;
404 case '#change-project-name':
405 data['projectName'] = $scope.projectName;
406 alertText = "You have changed the project name to: <b>" + $scope.projectName + "</b>";
407 alertZone = $scope.zone3alerts;
408 break;
409 case '#change-project-version':
410 data['projectVersion'] = $scope.projectVersion;
411 alertText = "You have changed the release to: ";
412 alertZone = $scope.zone3alerts;
413 break;
414 default:
415 throw "FIXME: implement conversion for element " + elementid;
416 }
417
418 console.log("calling edit with ", data);
419 $scope._makeXHRCall({
420 method: "POST", url: $scope.urls.xhr_edit, data: data,
421 }).then( function () {
422 $scope.toggle(elementid);
423 if (data['projectVersion'] != undefined) {
424 alertText += "<b>" + $scope.release.name + "</b>";
425 }
426 $scope.displayAlert(alertZone, alertText, "alert-info");
427 });
428 }
429
430
431 $scope.executeCommands = function() {
432 cmd = $location.path();
433
434 function _cmdExecuteWithParam(param, f) {
435 if (cmd.indexOf(param)==0) {
436 if (cmd.indexOf("=") > -1) {
437 var parameter = cmd.split("=", 2)[1];
438 if (parameter != undefined && parameter.length > 0) {
439 f(parameter);
440 }
441 } else {
442 f();
443 };
444 }
445 }
446
447 _cmdExecuteWithParam("/newproject", function () {
448 $scope.displayAlert($scope.zone1alerts,
449 "Your project <strong>" + $scope.project.name +
450 "</strong> has been created. You can now <a href=\""+ $scope.urls.layers +
451 "\">add layers</a> and <a href=\""+ $scope.urls.targets +
452 "\">select targets</a> you want to build.", "alert-success");
453 });
454
455 _cmdExecuteWithParam("/targetbuild=", function (targets) {
456 var oldTargetName = $scope.targetName;
457 $scope.targetName = targets.split(",").join(" ");
458 $scope.targetNamedBuild();
459 $scope.targetName = oldTargetName;
460 });
461
462 _cmdExecuteWithParam("/machineselect=", function (machine) {
463 $scope.machineName = machine;
464 $scope.toggle('#select-machine');
465 });
466
467
468 _cmdExecuteWithParam("/layeradd=", function (layer) {
469 angular.forEach(layer.split(","), function (l) {
470 $scope.layerAddId = l;
471 $scope.layerAdd();
472 });
473 });
474 }
475
476 $scope.displayAlert = function(zone, text, type) {
477 if (zone.maxid === undefined) { zone.maxid = 0; }
478 var crtid = zone.maxid ++;
479 angular.forEach(zone, function (o) { o.close() });
480 o = {
481 id: crtid, text: $sce.trustAsHtml(text), type: type,
482 close: function() {
483 zone.splice((function(id){ for (var i = 0; i < zone.length; i++) if (id == zone[i].id) { return i}; return undefined;})(crtid), 1);
484 },
485 }
486 zone.push(o);
487 return o;
488 }
489
490 $scope.toggle = function(id) {
491 $scope.projectName = $scope.project.name;
492 $scope.projectVersion = $scope.project.release.id;
493 $scope.machineName = $scope.machine.name;
494
495 angular.element(id).toggle();
496 angular.element(id+"-opposite").toggle();
497 }
498
499 $scope.selectedMostBuildTargets = function () {
500 keys = Object.keys($scope.mostBuiltTargets);
501 keys = keys.filter(function (e) { if ($scope.mostBuiltTargets[e]) return e });
502 return keys.length == 0;
503
504 }
505
506 // init code
507 //
508 $scope.init = function() {
509 $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "POST", url: $scope.urls.xhr_edit, data: undefined});}, 4000, 0);
510 }
511
512 $scope.init();
513});
514
515
516/**
517 TESTING CODE
518*/
519
520function test_diff_arrays() {
521 _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);})
522}
523
524var s = undefined;
525
526function test_set_alert(text) {
527 s = angular.element("div#main").scope();
528 s.displayAlert(s.zone3alerts, text);
529 console.log(s.zone3alerts);
530 s.$digest();
531}