diff options
author | Alexandru DAMIAN <alexandru.damian@intel.com> | 2014-09-09 11:47:13 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2014-10-30 13:39:49 +0000 |
commit | 960580cb70ab1c775b49f8a40d41632c080b3cbb (patch) | |
tree | 173570e0a9a80b14926c9dbbac995a39c49fbdcb /bitbake/lib/toaster/toastergui/static | |
parent | 1a463ab98ec1220b22a721a1f88ff5af61c33dc3 (diff) | |
download | poky-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.css | 60 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/projectapp.js | 531 |
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; } |
101 | select { width: auto; } | 110 | select { 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; } |
133 | fieldset { padding-left: 19px; } | 148 | fieldset { 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; } |
136 | input.huge { font-size: 17.5px; padding: 11px 19px; } | 151 | input.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; } | ||
138 | a code { color: #0088CC; } | 158 | a code { color: #0088CC; } |
139 | a code:hover { color: #005580; } | 159 | a 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; } |
146 | dd form { margin: 10px 0 0 0; } | 168 | dd form { margin: 10px 0 0 0; } |
169 | dd form { margin-bottom: 0px; } | ||
170 | dl 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; } | ||
185 | dd > 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 | |||
19 | angular_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 | */ | ||
77 | function _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 | |||
87 | var projectApp = angular.module('project', ['ui.bootstrap', 'ngCookies'], angular_formpost); | ||
88 | |||
89 | // modify the template tag markers to prevent conflicts with Django | ||
90 | projectApp.config(function($interpolateProvider) { | ||
91 | $interpolateProvider.startSymbol("{["); | ||
92 | $interpolateProvider.endSymbol("]}"); | ||
93 | }); | ||
94 | |||
95 | // main controller for the project page | ||
96 | projectApp.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 | |||
520 | function 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 | |||
524 | var s = undefined; | ||
525 | |||
526 | function 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 | } | ||