summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2014-10-02 17:58:15 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-11-12 17:04:48 +0000
commit42afeb422ea0a5e226cef586353d194d0339bbd7 (patch)
tree86bc1c6716b6b60bb4f77ebd9fa9d044da0daf7a
parent46f1fbe3abb3677861178b7008bf5edf73125197 (diff)
downloadpoky-42afeb422ea0a5e226cef586353d194d0339bbd7.tar.gz
bitbake: toastergui: Various fixes for projects, layers and targets page
This is a combined set of fixes for the project, layers and targets pages in the project section of toaster. The fixes correct behaviour and look in various parts of the page, including submitting XHR commands and updating the DOM with the correct info. (Bitbake rev: 96d7738f964784871c928c376cb9fbc9a275cf00) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/toaster/bldcontrol/models.py33
-rw-r--r--bitbake/lib/toaster/toastergui/static/css/default.css4
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projectapp.js24
-rw-r--r--bitbake/lib/toaster/toastergui/templates/base.html3
-rw-r--r--bitbake/lib/toaster/toastergui/templates/basetable_bottom.html13
-rw-r--r--bitbake/lib/toaster/toastergui/templates/layers.html124
-rw-r--r--bitbake/lib/toaster/toastergui/templates/mrb_section.html11
-rw-r--r--bitbake/lib/toaster/toastergui/templates/project.html48
-rw-r--r--bitbake/lib/toaster/toastergui/templates/targets.html340
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py157
10 files changed, 458 insertions, 299 deletions
diff --git a/bitbake/lib/toaster/bldcontrol/models.py b/bitbake/lib/toaster/bldcontrol/models.py
index f72fb8fbc9..e643d08603 100644
--- a/bitbake/lib/toaster/bldcontrol/models.py
+++ b/bitbake/lib/toaster/bldcontrol/models.py
@@ -42,11 +42,34 @@ class BuildEnvironment(models.Model):
42 42
43 def get_artifact_type(self, path): 43 def get_artifact_type(self, path):
44 if self.betype == BuildEnvironment.TYPE_LOCAL: 44 if self.betype == BuildEnvironment.TYPE_LOCAL:
45 import magic 45 try:
46 m = magic.open(magic.MAGIC_MIME_TYPE) 46 import magic
47 m.load() 47
48 return m.file(path) 48 # fair warning: this is a mess; there are multiple competeing and incompatible
49 raise Exception("FIXME: not implemented") 49 # magic modules floating around, so we try some of the most common combinations
50
51 try: # we try ubuntu's python-magic 5.4
52 m = magic.open(magic.MAGIC_MIME_TYPE)
53 m.load()
54 return m.file(path)
55 except AttributeError:
56 pass
57
58 try: # we try python-magic 0.4.6
59 m = magic.Magic(magic.MAGIC_MIME)
60 return m.from_file(path)
61 except AttributeError:
62 pass
63
64 try: # we try pip filemagic 1.6
65 m = magic.Magic(flags=magic.MAGIC_MIME_TYPE)
66 return m.id_filename(path)
67 except AttributeError:
68 pass
69
70 return "binary/octet-stream"
71 except ImportError:
72 return "binary/octet-stream"
50 73
51 def get_artifact(self, path): 74 def get_artifact(self, path):
52 if self.betype == BuildEnvironment.TYPE_LOCAL: 75 if self.betype == BuildEnvironment.TYPE_LOCAL:
diff --git a/bitbake/lib/toaster/toastergui/static/css/default.css b/bitbake/lib/toaster/toastergui/static/css/default.css
index 9e62c6c8e7..fb20fc9241 100644
--- a/bitbake/lib/toaster/toastergui/static/css/default.css
+++ b/bitbake/lib/toaster/toastergui/static/css/default.css
@@ -61,8 +61,8 @@ dd p { line-height: 20px; }
61 61
62/* Override default Twitter Boostrap styles for anchor tags inside tables */ 62/* Override default Twitter Boostrap styles for anchor tags inside tables */
63td a, td a > code { color: #333333; } 63td a, td a > code { color: #333333; }
64td a > code { white-space: normal; } 64td code { white-space: normal; }
65td a:hover { color: #000000; text-decoration: underline; } 65td a:hover, td a > code:hover { color: #000000; text-decoration: underline; }
66 66
67/* Override default Twitter Bootstrap styles for tr.error */ 67/* Override default Twitter Bootstrap styles for tr.error */
68.table tbody tr.error > td { background-color: transparent; } /* override default Bootstrap behaviour */ 68.table tbody tr.error > td { background-color: transparent; } /* override default Bootstrap behaviour */
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectapp.js b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
index e674d8ffd1..b347451e88 100644
--- a/bitbake/lib/toaster/toastergui/static/js/projectapp.js
+++ b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
@@ -92,6 +92,24 @@ projectApp.config(function($interpolateProvider) {
92 $interpolateProvider.endSymbol("]}"); 92 $interpolateProvider.endSymbol("]}");
93}); 93});
94 94
95
96// add time interval to HH:mm filter
97projectApp.filter('timediff', function() {
98 return function(input) {
99 function pad(j) {
100 if (parseInt(j) < 10) {return "0" + j}
101 return j;
102 }
103 seconds = parseInt(input);
104 minutes = Math.floor(seconds / 60);
105 seconds = seconds - minutes * 60;
106 hours = Math.floor(seconds / 3600);
107 seconds = seconds - hours * 3600;
108 return pad(hours) + ":" + pad(minutes) + ":" + pad(seconds);
109 }
110});
111
112
95// main controller for the project page 113// main controller for the project page
96projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $q, $sce) { 114projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $q, $sce) {
97 115
@@ -150,7 +168,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
150 168
151 // identify canceled builds here, so we can display them. 169 // identify canceled builds here, so we can display them.
152 _diffArrays(oldbuilds, $scope.builds, 170 _diffArrays(oldbuilds, $scope.builds,
153 function (e,f) { return e.status == f.status && e.id == f.id }, // compare 171 function (e,f) { return e.id == f.id }, // compare
154 undefined, // added 172 undefined, // added
155 function (e) { // deleted 173 function (e) { // deleted
156 if (e.status == "deleted") return; 174 if (e.status == "deleted") return;
@@ -421,7 +439,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
421 }).then( function () { 439 }).then( function () {
422 $scope.toggle(elementid); 440 $scope.toggle(elementid);
423 if (data['projectVersion'] != undefined) { 441 if (data['projectVersion'] != undefined) {
424 alertText += "<b>" + $scope.release.name + "</b>"; 442 alertText += "<b>" + $scope.project.release.name + "</b>";
425 } 443 }
426 $scope.displayAlert(alertZone, alertText, "alert-info"); 444 $scope.displayAlert(alertZone, alertText, "alert-info");
427 }); 445 });
@@ -506,7 +524,7 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
506 // init code 524 // init code
507 // 525 //
508 $scope.init = function() { 526 $scope.init = function() {
509 $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "POST", url: $scope.urls.xhr_edit, data: undefined});}, 4000, 0); 527 $scope.pollHandle = $interval(function () { $scope._makeXHRCall({method: "GET", url: $scope.urls.xhr_edit, data: undefined});}, 4000, 0);
510 } 528 }
511 529
512 $scope.init(); 530 $scope.init();
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html
index d414bfbbde..f377081849 100644
--- a/bitbake/lib/toaster/toastergui/templates/base.html
+++ b/bitbake/lib/toaster/toastergui/templates/base.html
@@ -1,6 +1,6 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2{% load static %} 2{% load static %}
3<html> 3<html lang="en">
4 <head> 4 <head>
5 <title>{% if objectname %} {{objectname|title}} - {% endif %}Toaster</title> 5 <title>{% if objectname %} {{objectname|title}} - {% endif %}Toaster</title>
6<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css"> 6<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css">
@@ -9,6 +9,7 @@
9<link rel="stylesheet" href="{% static 'css/prettify.css' %}" type='text/css'> 9<link rel="stylesheet" href="{% static 'css/prettify.css' %}" type='text/css'>
10<link rel="stylesheet" href="{% static 'css/default.css' %}" type='text/css'> 10<link rel="stylesheet" href="{% static 'css/default.css' %}" type='text/css'>
11<meta name="viewport" content="width=device-width, initial-scale=1.0" /> 11<meta name="viewport" content="width=device-width, initial-scale=1.0" />
12<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
12<script src="{% static 'js/jquery-2.0.3.min.js' %}"> 13<script src="{% static 'js/jquery-2.0.3.min.js' %}">
13</script> 14</script>
14<script src="{% static 'js/jquery.cookie.js' %}"> 15<script src="{% static 'js/jquery.cookie.js' %}">
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html
index 091e11a51e..d48ad92020 100644
--- a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html
+++ b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html
@@ -58,9 +58,12 @@
58 } 58 }
59 59
60 // load cookie for number of entries to be displayed on page 60 // load cookie for number of entries to be displayed on page
61 pagesize = $.cookie('count'); 61 if ({{request.GET.count}} != "") {
62 if (!pagesize) 62 pagesize = {{request.GET.count}};
63 pagesize = 10; 63 } else {
64 pagesize = $.cookie('_count');
65 }
66
64 $('.pagesize option').prop('selected', false) 67 $('.pagesize option').prop('selected', false)
65 .filter('[value="' + pagesize + '"]') 68 .filter('[value="' + pagesize + '"]')
66 .attr('selected', true); 69 .attr('selected', true);
@@ -81,9 +84,9 @@
81 $('.progress, .lead span').tooltip({container:'table', placement:'top'}); 84 $('.progress, .lead span').tooltip({container:'table', placement:'top'});
82 85
83 $(".pagesize").change(function () { 86 $(".pagesize").change(function () {
84 reload_params({"count":$(this).val()});
85 // save cookie with pagesize 87 // save cookie with pagesize
86 $.cookie("count", $(this).val(), { path : $(location).attr('pathname') }); 88 $.cookie("_count", $(this).val(), { path : $(location).attr('pathname') });
89 reload_params({"count":$(this).val()});
87 }); 90 });
88}); 91});
89</script> 92</script>
diff --git a/bitbake/lib/toaster/toastergui/templates/layers.html b/bitbake/lib/toaster/toastergui/templates/layers.html
index 51f4dd96e7..db34fe4818 100644
--- a/bitbake/lib/toaster/toastergui/templates/layers.html
+++ b/bitbake/lib/toaster/toastergui/templates/layers.html
@@ -9,67 +9,66 @@
9{% block projectinfomain %} 9{% block projectinfomain %}
10 <div class="page-header"> 10 <div class="page-header">
11 <h1> 11 <h1>
12 {% if request.GET.search and objects.paginator.count > 0 %} 12 {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %}
13 {{objects.paginator.count}} layer{{objects.paginator.count|pluralize}} found 13 {{objects.paginator.count}} layer{{objects.paginator.count|pluralize}} found
14 {%elif request.GET.search and objects.paginator.count == 0%} 14 {% elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %}
15 No layer found 15 No layers found
16 {%else%} 16 {%else%}
17 All layers 17 All layers
18 {%endif%} 18 {%endif%}
19 <i class="icon-question-sign get-help heading-help" title="This page lists all the layers compatible with " + {{project.release.name}} + " that Toaster knows about."></i> 19 <i class="icon-question-sign get-help heading-help" title="This page lists all the layers compatible with {{project.release.name}} that Toaster knows about."></i>
20 </h1> 20 </h1>
21 </div> 21 </div>
22 22
23 <div id="zone1alerts"> 23 <div id="zone1alerts">
24
25 </div> 24 </div>
26 25
27 26
28 <div id="layer-added" class="alert alert-info lead" style="display:none;"></div>
29
30
31{% include "basetable_top_layers.html" %} 27{% include "basetable_top_layers.html" %}
32 {% for lv in objects %} 28 {% for o in objects %}
33 <tr class="data"> 29 <tr class="data">
34 <td class="layer"><a href="{% url 'layerdetails' lv.id %}">{{lv.layer.name}}</a></td> 30 <td class="layer"><a href="{% url 'layerdetails' o.id %}">{{o.layer.name}}</a></td>
35 <td class="description">{{lv.layer.summary}}</td> 31 <td class="description">{% if o.layer.summary %}{{o.layer.summary}}{%endif%}</td>
36 <td class="source"><a href="{% url 'layerdetails' lv.pk %}">{{lv.layer_source.name}}</a></td> 32 <td class="source"><a href="{% url 'layerdetails' o.pk %}">{{o.layer_source.name}}</a></td>
37 <td class="git-repo"><a href="{% url 'layerdetails' lv.pk %}"><code>{{lv.layer.vcs_url}}</code></a> 33 <td class="git-repo"><a href="{% url 'layerdetails' o.pk %}"><code>{{o.layer.vcs_url}}</code></a>
38 {% if lv.get_vcs_link_url %} 34 {% if o.get_vcs_link_url %}
39 <a target="_blank" href="{{ lv.get_vcs_link_url }}"><i class="icon-share get-info"></i></a> 35 <a target="_blank" href="{{ o.get_vcs_link_url }}"><i class="icon-share get-info"></i></a>
40 {% endif %} 36 {% endif %}
41 </td> 37 </td>
42 <td class="git-subdir" style="display: table-cell;"><a href="{% url 'layerdetails' lv.pk %}"><code>{{lv.dirpath}}</code></a> 38 <td class="git-subdir" style="display: table-cell;"><a href="{% url 'layerdetails' o.pk %}"><code>{{o.dirpath}}</code></a>
43 {% if lv.dirpath and lv.get_vcs_dirpath_link_url %} 39 {% if o.dirpath and o.get_vcs_dirpath_link_url %}
44 <a target="_blank" href="{{ lv.get_vcs_dirpath_link_url }}"><i class="icon-share get-info"></i></a> 40 <a target="_blank" href="{{ o.get_vcs_dirpath_link_url }}"><i class="icon-share get-info"></i></a>
45 {% endif %} 41 {% endif %}
46 </td> 42 </td>
47 <td class="branch">{% if lv.branch %}{{lv.branch}}{% else %}{{lv.up_branch.name}}{% endif %}</td> 43 <td class="branch">{% if o.branch %}{{o.branch}}{% else %}{{o.up_branch.name}}{% endif %}</td>
48 <td class="dependencies"> 44 <td class="dependencies">
49 {% with lvds=lv.dependencies.all%} 45 {% with ods=o.dependencies.all%}
50 {% if lvds.count %} 46 {% if ods.count %}
51 <a class="btn" 47 <a class="btn"
52 title="<a href='{% url "layerdetails" lv.pk %}'>{{lv.layer.name}}</a> dependencies" 48 title="<a href='{% url "layerdetails" o.pk %}'>{{o.layer.name}}</a> dependencies"
53 data-content="<ul class='unstyled'> 49 data-content="<ul class='unstyled'>
54 {% for i in lvds%} 50 {% for i in ods%}
55 <li><a href='{% url "layerdetails" i.depends_on.pk %}'>{{i.depends_on.layer.name}}</a></li> 51 <li><a href='{% url "layerdetails" i.depends_on.pk %}'>{{i.depends_on.layer.name}}</a></li>
56 {% endfor %} 52 {% endfor %}
57 </ul>"> 53 </ul>">
58 {{lvds.count}} 54 {{ods.count}}
59 </a> 55 </a>
60 {% endif %} 56 {% endif %}
61 {% endwith %} 57 {% endwith %}
62 </td> 58 </td>
63 <td class="add-del-layers" value="{{lv.pk}}"> 59 {% if project %}
64 <button id="layer-del-{{lv.pk}}" class="btn btn-danger btn-block remove-layer" style="display:none;" onclick="layerDel({{lv.pk}}, '{{lv.layer.name}}', '{%url 'layerdetails' lv.pk%}')"> 60 <td class="add-del-layers" value="{{o.pk}}">
61 <div id="layer-tooltip-{{o.pk}}" style="display: none; font-size: 11px; line-height: 1.3;" class="tooltip-inner">layer was modified</div>
62 <button id="layer-del-{{o.pk}}" class="btn btn-danger btn-block remove-layer layerbtn" style="display:none;" onclick="layerDel({{o.pk}}, '{{o.layer.name}}', '{%url 'layerdetails' o.pk%}')" >
65 <i class="icon-trash"></i> 63 <i class="icon-trash"></i>
66 Delete layer 64 Delete layer
67 </button> 65 </button>
68 <button id="layer-add-{{lv.pk}}" class="btn btn-block" style="display:none;" onclick="layerAdd({{lv.pk}}, '{{lv.layer.name}}', '{%url 'layerdetails' lv.pk%}')" > 66 <button id="layer-add-{{o.pk}}" class="btn btn-block layerbtn" style="display:none;" onclick="layerAdd({{o.pk}}, '{{o.layer.name}}', '{%url 'layerdetails' o.pk%}')" title="layer added">
69 <i class="icon-plus"></i> 67 <i class="icon-plus"></i>
70 Add layer 68 Add layer
71 </button> 69 </button>
72 </td> 70 </td>
71 {% endif %}
73 </tr> 72 </tr>
74 {% endfor %} 73 {% endfor %}
75{% include "basetable_bottom.html" %} 74{% include "basetable_bottom.html" %}
@@ -78,7 +77,7 @@
78 77
79 <!-- 'Layer dependencies modal' --> 78 <!-- 'Layer dependencies modal' -->
80 <div id="dependencies_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true"> 79 <div id="dependencies_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">
81 <form id="dependencies_modal_form"> 80 <form id="dependencies_modal_form" style="margin: 0px">
82 <div class="modal-header"> 81 <div class="modal-header">
83 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> 82 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
84 <h3><span class="layer-name"></span> dependencies</h3> 83 <h3><span class="layer-name"></span> dependencies</h3>
@@ -95,8 +94,11 @@
95 </form> 94 </form>
96 </div> 95 </div>
97 96
97{% if project %}
98<script> 98<script>
99 99
100var tooltipUpdateText;
101
100function _makeXHREditCall(data, onsuccess, onfail) { 102function _makeXHREditCall(data, onsuccess, onfail) {
101 $.ajax( { 103 $.ajax( {
102 type: "POST", 104 type: "POST",
@@ -120,13 +122,14 @@ function _makeXHREditCall(data, onsuccess, onfail) {
120 122
121 123
122function layerDel(layerId, layerName, layerURL) { 124function layerDel(layerId, layerName, layerURL) {
125 tooltipUpdateText = "1 layer deleted";
123 _makeXHREditCall({ 'layerDel': layerId }, function () { 126 _makeXHREditCall({ 'layerDel': layerId }, function () {
124 show_alert("<strong>1</strong> layer deleted from <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>: <a href=\""+layerURL+"\">" + layerName +"</a>"); 127 show_alert("You have deleted <strong>1</strong> layer from <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>: <a href=\""+layerURL+"\">" + layerName +"</a>");
125 }); 128 });
126} 129}
127 130
128function show_alert(text, cls) { 131function show_alert(text, cls) {
129 $("#zone1alerts").html("<div class=\"alert alert-info\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\">&times;</button>" + text + "</div>"); 132 $("#zone1alerts").html("<div class=\"alert alert-info lead\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\">&times;</button>" + text + "</div>");
130} 133}
131 134
132function show_dependencies_modal(layerId, layerName, layerURL, dependencies) { 135function show_dependencies_modal(layerId, layerName, layerURL, dependencies) {
@@ -142,25 +145,35 @@ function show_dependencies_modal(layerId, layerName, layerURL, dependencies) {
142 } 145 }
143 $('#dependencies_list').html(deplistHtml); 146 $('#dependencies_list').html(deplistHtml);
144 147
148 var selected = [layerId];
149 var layer_link_list = "<a href='"+layerURL+"'>"+layerName+"</a>";
150
145 $("#dependencies_modal_form").submit(function (e) { 151 $("#dependencies_modal_form").submit(function (e) {
146 e.preventDefault(); 152 e.preventDefault();
147 var selected = [layerId];
148 $("input[name='dependencies']:checked").map(function () { selected.push(parseInt($(this).val()))}); 153 $("input[name='dependencies']:checked").map(function () { selected.push(parseInt($(this).val()))});
154 if (selected.length > 1) {
155 tooltipUpdateText = "" + selected.length + " layers added";
156 } else {
157 tooltipUpdateText = "1 layer added";
158 }
149 159
150 _makeXHREditCall({ 'layerAdd': selected.join(",") }, function () { 160 for (var i = 0; i < selected.length; i++) {
151 var layer_link_list = "<a href='"+layerURL+"'>"+layerName+"</a>"; 161 for (var j = 0; j < dependencies.length; j++) {
152 for (var i = 0; i < selected.length; i++) { 162 if (dependencies[j].id == selected[i]) {
153 for (var j = 0; j < dependencies.length; i++) { 163 layer_link_list+= ", <a href='"+dependencies[j].layerdetailurl+"'>"+dependencies[j].name+"</a>"
154 if (dependencies[j].id == selected[i]) { 164 break;
155 layer_link_list+= ", <a href='"+dependencies[j].layerdetailurl+"'>"+dependencies[j].name+"</a>"
156 break;
157 }
158 } 165 }
159 } 166 }
167 }
168
169 $('#dependencies_modal').modal('hide');
160 170
161 $('#dependencies_modal').modal('hide'); 171 {% if project %}
162 show_alert("<strong>"+selected.length+"</strong> layers added to <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>:" + layer_link_list); 172 _makeXHREditCall({ 'layerAdd': selected.join(",") }, function () {
173 show_alert("You have added <strong>"+selected.length+"</strong> layers to <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>: " + layer_link_list);
163 }); 174 });
175 {% endif %}
176
164 }); 177 });
165 $('#dependencies_modal').modal('show'); 178 $('#dependencies_modal').modal('show');
166} 179}
@@ -178,8 +191,9 @@ function layerAdd(layerId, layerName, layerURL) {
178 show_dependencies_modal(layerId, layerName, layerURL, _data.list); 191 show_dependencies_modal(layerId, layerName, layerURL, _data.list);
179 } 192 }
180 else { 193 else {
194 tooltipUpdateText = "1 layer added";
181 _makeXHREditCall({ 'layerAdd': layerId }, function () { 195 _makeXHREditCall({ 'layerAdd': layerId }, function () {
182 show_alert("<strong>1</strong> layer added to <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>: <a href=\""+layerURL+"\">" + layerName +"</a>"); 196 show_alert("You have added <strong>1</strong> layer to <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>: <a href=\""+layerURL+"\">" + layerName +"</a>");
183 }); 197 });
184 } 198 }
185 } 199 }
@@ -188,15 +202,31 @@ function layerAdd(layerId, layerName, layerURL) {
188} 202}
189 203
190function button_set(id, state) { 204function button_set(id, state) {
205 var tohide, toshow;
191 if (state == "add") 206 if (state == "add")
192 { 207 {
193 $("#layer-add-" + id).show(); 208 tohide = "#layer-del-";
194 $("#layer-del-" + id).hide(); 209 toshow = "#layer-add-";
195 } 210 }
196 else if (state == "del") 211 else if (state == "del")
197 { 212 {
198 $("#layer-add-" + id).hide(); 213 tohide = "#layer-add-";
199 $("#layer-del-" + id).show(); 214 toshow = "#layer-del-";
215 }
216
217
218 var previouslyvisible = $(tohide + id).is(":visible");
219 if (previouslyvisible) {
220 $(tohide + id).fadeOut( function() {
221 $("#layer-tooltip-" + id).text(tooltipUpdateText);
222 $("#layer-tooltip-" + id).fadeIn().delay(2000).fadeOut(function(){
223 $(toshow + id).delay(300).fadeIn();
224 });
225 });
226 } else {
227 $(tohide + id).hide();
228 $("#layer-tooltip-" + id).hide();
229 $(toshow + id).show();
200 } 230 }
201}; 231};
202 232
@@ -214,9 +244,11 @@ function updateButtons(projectLayers) {
214} 244}
215 245
216$(document).ready(function (){ 246$(document).ready(function (){
247 $('.layerbtn').tooltip({ trigger: 'manual' });
217 updateButtons({{projectlayerset}}); 248 updateButtons({{projectlayerset}});
218}); 249});
219 250
220</script> 251</script>
252{%endif%}
221 253
222{% endblock %} 254{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
index 3d17ac62e4..586c47bfae 100644
--- a/bitbake/lib/toaster/toastergui/templates/mrb_section.html
+++ b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
@@ -44,7 +44,7 @@
44 Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a> 44 Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a>
45 </span> 45 </span>
46 {% if build.project %} 46 {% if build.project %}
47 <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%elif build.outcome == build.FAILED%}btn-danger{%else%}btn-info{%endif%} pull-right" onclick="scheduleBuild({%url 'xhr_projectbuild' build.project.id as myurl %}{{myurl|json}}, {{build.project.name|json}}, {{build.get_sorted_target_list|mapselect:'target'|json}})">Run again</a> 47 <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%elif build.outcome == build.FAILED%}btn-danger{%else%}btn-info{%endif%} pull-right" onclick="scheduleBuild({% url 'xhr_projectbuild' build.project.id as bpi%}{{bpi|json}}, {{build.project.name|json}}, {{build.get_sorted_target_list|mapselect:'target'|json}})">Run again</a>
48 {% endif %} 48 {% endif %}
49 </div> 49 </div>
50 {%endif%} 50 {%endif%}
@@ -81,19 +81,18 @@ function _makeXHRBuildCall(url, data, onsuccess, onfail) {
81 alert("Call failed"); 81 alert("Call failed");
82 console.log(_data); 82 console.log(_data);
83 if (onfail) onfail(data); 83 if (onfail) onfail(data);
84 } 84 } });
85 });
86} 85}
87 86
88 87
89function scheduleBuild(url, projectName, buildlist) { 88function scheduleBuild(url, projectName, buildlist) {
90 console.log("scheduleBuild"); 89 console.log("scheduleBuild");
91// _makeXHRBuildCall(url , {targets: buildlist.join(" ")}, function (_data) { 90 _makeXHRBuildCall(url, {targets: buildlist.join(" ")}, function (_data) {
92 91
93 $('#latest-builds').prepend('<div class="alert alert-info" style="padding-top:0px">' + '<span class="label label-info" style="font-weight: normal; margin-bottom: 5px; margin-left:-15px; padding-top:5px;">'+projectName+'</span><div class="row-fluid">' + 92 $('#latest-builds').prepend('<div class="alert alert-info" style="padding-top:0px">' + '<span class="label label-info" style="font-weight: normal; margin-bottom: 5px; margin-left:-15px; padding-top:5px;">'+projectName+'</span><div class="row-fluid">' +
94 '<div class="span4 lead">' + buildlist.join(" ") + 93 '<div class="span4 lead">' + buildlist.join(" ") +
95 '</div><div class="span4 lead pull-right">Build queued. Your build will start shortly.</div></div></div>'); 94 '</div><div class="span4 lead pull-right">Build queued. Your build will start shortly.</div></div></div>');
96// } 95 });
97} 96}
98 97
99</script> 98</script>
diff --git a/bitbake/lib/toaster/toastergui/templates/project.html b/bitbake/lib/toaster/toastergui/templates/project.html
index 9399b312ca..6a812834d3 100644
--- a/bitbake/lib/toaster/toastergui/templates/project.html
+++ b/bitbake/lib/toaster/toastergui/templates/project.html
@@ -76,6 +76,14 @@ vim: expandtab tabstop=2
76 </div> 76 </div>
77 </script> 77 </script>
78 78
79 <script type="text/ng-template" id="target_display">
80 <div ng-switch on="t.task.length">
81 <div ng-switch-when="0">{[t.target]}</div>
82 <div ng-switch-default>{[t.target]}:{[t.task]}</div>
83 </div>
84 </script>
85
86
79 <!-- build form --> 87 <!-- build form -->
80 <div class="well"> 88 <div class="well">
81 <form class="build-form" ng-submit="targetNamedBuild()"> 89 <form class="build-form" ng-submit="targetNamedBuild()">
@@ -99,11 +107,11 @@ vim: expandtab tabstop=2
99 107
100 <h2 class="air" ng-if="builds.length">Latest builds</h2> 108 <h2 class="air" ng-if="builds.length">Latest builds</h2>
101 109
102 <div class="alert" ng-repeat="b in builds" ng-class="{'queued':'alert-info', 'deleted':'alert-info', 'in progress': 'alert-info', 'In Progress':'alert-info', 'Succeeded':'alert-success', 'failed':'alert-error', 'Failed':'alert-error'}[b.status]"> 110 <div class="alert" ng-repeat="b in builds" ng-class="{'queued':'alert-info', 'deleted':'alert-info', 'in progress': 'alert-info', 'failed':'alert-error', 'completed':{'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.build[0].status]}[b.status]" >
103 <div class="row-fluid"> 111 <div class="row-fluid">
104 <switch ng-switch="b.status"> 112 <switch ng-switch="b.status">
105 <case ng-switch-when="failed"> 113 <case ng-switch-when="failed">
106 <div class="lead span3"> <span ng-repeat="t in b.targets">{[t.target]} </span> </div> 114 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
107 <div class="row-fluid"> 115 <div class="row-fluid">
108 <div class="air well" ng-repeat="e in b.errors"> 116 <div class="air well" ng-repeat="e in b.errors">
109 {[e.type]}: <pre>{[e.msg]}</pre> 117 {[e.type]}: <pre>{[e.msg]}</pre>
@@ -111,53 +119,51 @@ vim: expandtab tabstop=2
111 </div> 119 </div>
112 </case> 120 </case>
113 <case ng-switch-when="queued"> 121 <case ng-switch-when="queued">
114 <div class="lead span5"> <span ng-repeat="t in b.targets">{[t.target]} </span> </div> 122 <div class="lead span5"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
115 <div class="span4 lead" >Build queued 123 <div class="span4 lead" >Build queued
116 <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> 124 <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>
117 </div> 125 </div>
118 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button> 126 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button>
119 </case> 127 </case>
120 <case ng-switch-when="created"> 128 <case ng-switch-when="created">
121 <div class="lead span3"> <span ng-repeat="t in b.targets">{[t.target]} </span> </div> 129 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
122 <div class="span6" > 130 <div class="span6" >
123 <span class="lead">Creating build</span> 131 <span class="lead">Creating build</span>
124 </div> 132 </div>
125 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button> 133 <button class="btn pull-right btn-info" ng-click="buildCancel(b.id)">Cancel</button>
126 </case> 134 </case>
127 <case ng-switch-when="deleted"> 135 <case ng-switch-when="deleted">
128 <div class="lead span3"> <span ng-repeat="t in b.targets">{[t.target]} </span> </div> 136 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
129 <div class="span6" id="{[b.id]}-deleted" > 137 <div class="span6" id="{[b.id]}-deleted" >
130 <span class="lead">Build deleted</span> 138 <span class="lead">Build deleted</span>
131 </div> 139 </div>
132 <button class="btn pull-right btn-info" ng-click="builds.splice(builds.indexOf(b), 1)">Close</button> 140 <button class="btn pull-right btn-info" ng-click="builds.splice(builds.indexOf(b), 1)">Close</button>
133 </case> 141 </case>
134 <case ng-switch-when="in progress"> 142 <case ng-switch-when="in progress">
135 <div class="lead span3"> <span ng-repeat="t in b.targets">{[t.target]} </span> </div> 143 <div class="lead span3"> <span ng-repeat="t in b.targets" ng-include src="'target_display'"></span> </div>
136 <div class="span4" >
137 </div>
138 <div class="lead pull-right">Build starting shortly</div>
139 </case>
140 <case ng-switch-when="In Progress">
141 <div class="span4" > 144 <div class="span4" >
142 <div class="progress" style="margin-top:5px;" data-toggle="tooltip" tooltip="{[b.completeper]}% of tasks complete"> 145 <div class="progress" style="margin-top:5px;" data-toggle="tooltip" tooltip="{[b.build[0].completeper]}% of tasks complete">
143 <div style="width: {[b.completeper]}%;" class="bar"></div> 146 <div style="width: {[b.build[0].completeper]}%;" class="bar"></div>
144 </div> 147 </div>
145 </div> 148 </div>
146 <div class="lead pull-right">ETA: at {[b.eta]}</div> 149 <div class="lead pull-right">ETA: at {[b.build[0].eta|date:"shortDate"]}</div>
147 </case> 150 </case>
148 <case ng-switch-default=""> 151 <case ng-switch-when="completed">
149 <div class="lead span3"><a href="{[b.build_page_url]}"><span ng-repeat="t in b.targets">{[t.target]} </span> </div></a> 152 <div class="lead span3"><a href="{[b.build[0].build_page_url]}"><span ng-repeat="t in b.targets" ng-include src="'target_display'"></span></a></div>
150 <div class="span2 lead"> 153 <div class="span2 lead">
151 {[b.completed_on|date:'dd/MM/yy HH:mm']} 154 {[b.build[0].completed_on|date:'dd/MM/yy HH:mm']}
152 </div> 155 </div>
153 <div class="span2"><span>{[b.errors.len]}</span></div> 156 <div class="span2"><span><a href="{[b.build[0].build_page_url]}#errors" class="lead error" ng-if="b.build[0].errors">{[b.build[0].errors]}</a></span></div>
154 <div class="span2"><span>{[b.warnings.len]}</span></div> 157 <div class="span2"><span><a href="{[b.build[0].build_page_url]}#warnings" class="lead warning" ng-if="b.build[0].warnings">{[b.build[0].warnings]}</a></span></div>
155 <div> <span class="lead">Build time: {[b.build_time|date:"HH:mm"]}</span> 158 <div> <span class="lead">Build time: {[b.build[0].build_time|timediff]}</span>
156 <button class="btn pull-right" ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.status]" 159 <button class="btn pull-right" ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]"
157 ng-click="targetExistingBuild(b.targets)">Run again</button> 160 ng-click="targetExistingBuild(b.targets)">Run again</button>
158 161
159 </div> 162 </div>
160 </case> 163 </case>
164 <case ng-switch-default="">
165 <div>FIXME!</div>
166 </case>
161 </switch> 167 </switch>
162 <div class="lead pull-right"> 168 <div class="lead pull-right">
163 </div> 169 </div>
diff --git a/bitbake/lib/toaster/toastergui/templates/targets.html b/bitbake/lib/toaster/toastergui/templates/targets.html
index 3afdf0a5e9..32a644a743 100644
--- a/bitbake/lib/toaster/toastergui/templates/targets.html
+++ b/bitbake/lib/toaster/toastergui/templates/targets.html
@@ -9,55 +9,74 @@
9{% block projectinfomain %} 9{% block projectinfomain %}
10 <div class="page-header"> 10 <div class="page-header">
11 <h1> 11 <h1>
12 All targets 12 {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %}
13 <i class="icon-question-sign get-help heading-help" title="This page lists all the targets compatible with Yocto Project 1.7 'Dxxxx' that Toaster knows about. They include community-created targets suitable for use on top of OpenEmbedded Core and any targets you have imported"></i> 13 {{objects.paginator.count}} target{{objects.paginator.count|pluralize}} found
14 {% elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %}
15 No targets found
16 {%else%}
17 All targets
18 {%endif%}
19 <i class="icon-question-sign get-help heading-help" title="This page lists all the targets compatible with " + {{project.release.name}} + " that Toaster knows about."></i>
14 </h1> 20 </h1>
15 </div> 21 </div>
16 <!--div class="alert">
17 <div class="input-append" style="margin-bottom:0px;">
18 <input class="input-xxlarge" type="text" placeholder="Search targets" value="browser" />
19 <a class="add-on btn">
20 <i class="icon-remove"></i>
21 </a>
22 <button class="btn" type="button">Search</button>
23 <a class="btn btn-link" href="#">Show all targets</a>
24 </div>
25 </div-->
26 <div id="target-added" class="alert alert-info lead" style="display:none;"></div>
27 <div id="target-removed" class="alert alert-info lead" style="display:none;">
28 <button type="button" class="close" data-dismiss="alert">&times;</button>
29 <strong>1</strong> target deleted from <a href="project-with-targets.html">your project</a>: <a href="#">meta-aarch64</a>
30 </div>
31 22
23 <div id="zone1alerts">
24
25 </div>
26
27{% if objects.paginator.count == 0 %}
28 <div class="row-fluid">
29 <div class="alert">
30 <form class="no-results input-append" id="searchform">
31 <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="add-on btn" tabindex="-1"><i class="icon-remove"></i></a>{% endif %}
32 <button class="btn" type="submit" value="Search">Search</button>
33 <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all targets</button>
34 </form>
35 </div>
36 </div>
37
38{% else %}
32 39
33{% include "basetable_top.html" %} 40{% include "basetable_top.html" %}
34 {% for o in objects %} 41 {% for o in objects %}
35 <tr class="data"> 42 <tr class="data">
36 <td class="target"> 43 <td class="target">
37 {{o.name}} ({{o.id}}, {{o.up_id}}) 44 {{o.name}}
38 <a target="_blank" href="{{o.get_layersource_view_url}}"><i class="icon-share get-info"></i></a> 45 <a target="_blank" href="{{o.get_layersource_view_url}}"><i class="icon-share get-info"></i></a>
39 </td> 46 </td>
40 <td class="version">{{o.version}}</td> 47 <td class="version">{{o.version}}</td>
41 <td class="description">{{o.description}}</td> 48 <td class="description">{% if o.description %}{{o.description}}{% else %}{{o.summary}}{%endif%}</td>
42 <td class="recipe-file"> 49 <td class="recipe-file">
43 <code>{{o.file_path}}</code> 50 <code>{{o.file_path}}</code>
44 <a href="{{o.get_vcs_link_url}}" target="_blank"><i class="icon-share get-info"></i></a> 51 <a href="{{o.get_vcs_link_url}}{{o.file_path}}" target="_blank"><i class="icon-share get-info"></i></a>
45 </td> 52 </td>
46 <td class="target-section">{{o.section}}</td> 53 <td class="target-section">{{o.section}}</td>
47 <td class="license">{{o.license}}</td> 54 <td class="license">{{o.license}}</td>
48 <td class="layer"><a href="#">{{o.layer_version.layer.name}}</a></td> 55 <td class="layer"><a href="{% url 'layerdetails' o.layer_version.id%}">{{o.layer_version.layer.name}}</a></td>
49 <td class="source">{{o.layer_source.name}}</td> 56 <td class="source">{{o.layer_source.name}}</td>
50 <td class="branch">{{o.layer_version.commit}}</td> 57 <td class="branch">
51 <td class="build"> 58 {% if o.layer_version.up_branch %}
52 <a id="build-target" href="project-with-targets.html?target=3g-router-image" class="btn btn-block" style="display:none;"> 59 {{o.layer_version.up_branch.name}}
53 Build target 60 {% else %}
54 </a> 61 <a class="btn"
55 <a id="add-layer" href="#" class="btn btn-block nopop" title="1 layer added"> 62 data-content="<ul class='unstyled'>
56 <i class="icon-plus"></i> 63 <li>{{o.layer_version.commit}}</li>
57 Add layer 64 </ul>">
58 <i class="icon-question-sign get-help" title="To build this target, you must first add the meta-embeddedgeeks layer to your project"></i> 65 {{o.layer_version.commit|truncatechars:13}}
59 </a> 66 </a>
60 </td> 67 {% endif %}
68 </td>
69 <td class="add-layer" value="{{o.pk}}" layerversion_id="{{o.layer_version.pk}}">
70 <div id="layer-tooltip-{{o.pk}}" style="display: none; font-size: 11px; line-height: 1.3;" class="tooltip-inner">layer was modified</div>
71 <a href="{% url 'project' project.id %}#/targetbuild={{o.name}}" id="target-build-{{o.pk}}" class="btn btn-block remove-layer" style="display:none;" >
72 Build target
73 </a>
74 <a id="layer-add-{{o.pk}}" class="btn btn-block" style="display:none;" href="javascript:layerAdd({{o.layer_version.pk}}, '{{o.layer_version.layer.name}}', '{%url 'layerdetails' o.layer_version.pk%}', {{o.pk}})" >
75 <i class="icon-plus"></i>
76 Add layer
77 <i title="" class="icon-question-sign get-help" data-original-title="To build this target, you must first add the {{o.layer_version.layer.name}} layer to your project"></i>
78 </a>
79 </td>
61 </tr> 80 </tr>
62 {% endfor %} 81 {% endfor %}
63{% include "basetable_bottom.html" %} 82{% include "basetable_bottom.html" %}
@@ -65,122 +84,177 @@
65 <!-- Modals --> 84 <!-- Modals -->
66 85
67 <!-- 'Layer dependencies modal' --> 86 <!-- 'Layer dependencies modal' -->
68 <div id="dependencies-message" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true"> 87 <div id="dependencies_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">
88 <form id="dependencies_modal_form">
69 <div class="modal-header"> 89 <div class="modal-header">
70 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> 90 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
71 <h3>meta-acer dependencies</h3> 91 <h3><span class="layer-name"></span> dependencies</h3>
72 </div> 92 </div>
73 <div class="modal-body"> 93 <div class="modal-body">
74 <p><strong>meta-acer</strong> depends on some targets that are not added to your project. Select the ones you want to add:</p> 94 <p><strong class="layer-name"></strong> depends on some layers that are not added to your project. Select the ones you want to add:</p>
75 <ul class="unstyled"> 95 <ul class="unstyled" id="dependencies_list">
76 <li>
77 <label class="checkbox">
78 <input type="checkbox" checked="checked">
79 meta-android
80 </label>
81 </li>
82 <li>
83 <label class="checkbox">
84 <input type="checkbox" checked="checked">
85 meta-oe
86 </label>
87 </li>
88 </ul> 96 </ul>
89 </div> 97 </div>
90 <div class="modal-footer"> 98 <div class="modal-footer">
91 <button id="add-target-dependencies" type="submit" class="btn btn-primary" data-dismiss="modal" >Add targets</button> 99 <button class="btn btn-primary" type="submit">Add layers</button>
92 <button class="btn" data-dismiss="modal">Cancel</button> 100 <button class="btn" type="reset" data-dismiss="modal">Cancel</button>
93 </div> 101 </div>
102 </form>
94 </div> 103 </div>
95 104
96 <script src="assets/js/jquery-1.9.1.min.js" type='text/javascript'></script> 105{% endif %}
97 <script src="assets/js/jquery.tablesorter.min.js" type='text/javascript'></script> 106
98 <script src="assets/js/jquery-ui-1.10.3.custom.min.js"></script> 107{% if project %}
99 <script src="assets/js/bootstrap.min.js" type='text/javascript'></script> 108<script>
100 <script src="assets/js/prettify.js" type='text/javascript'></script> 109
101 <script src="assets/js/jit.js" type='text/javascript'></script> 110var tooltipUpdateText;
102 <script src="assets/js/main.js" type='text/javascript'></script> 111
103 112function _makeXHREditCall(data, onsuccess, onfail) {
104 <script> 113 $.ajax( {
105 $(document).ready(function() { 114 type: "POST",
106 115 url: "{% url 'xhr_projectedit' project.id %}",
107 //show or hide selected columns on load 116 data: data,
108 $("input:checkbox").each(function(){ 117 headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
109 var selectedType = $(this).val(); 118 success: function (_data) {
110 if($(this).is(":checked")){ 119 if (_data.error != "ok") {
111 $("."+selectedType).show(); 120 alert(_data.error);
121 } else {
122 updateButtons(_data.layers.map(function (e) {return e.id}));
123 if (onsuccess != undefined) onsuccess(_data);
112 } 124 }
113 else{ 125 },
114 $("."+selectedType).hide(); 126 error: function (_data) {
127 alert("Call failed");
128 console.log(_data);
129 }
130 });
131}
132
133function show_alert(text, cls) {
134 $("#zone1alerts").html("<div class=\"alert alert-info lead\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\">&times;</button>" + text + "</div>");
135}
136
137
138function show_dependencies_modal(layerId, layerName, layerURL, dependencies) {
139 // update layer name
140 $('.layer-name').text(layerName);
141 var deplistHtml = "";
142 for (var i = 0; i < dependencies.length; i++) {
143 deplistHtml += "<li><label class=\"checkbox\"><input name=\"dependencies\" value=\""
144 deplistHtml += dependencies[i].id;
145 deplistHtml +="\" type=\"checkbox\" checked=\"checked\"/>";
146 deplistHtml += dependencies[i].name;
147 deplistHtml += "</label></li>";
148 }
149 $('#dependencies_list').html(deplistHtml);
150
151 var selected = [layerId];
152 var layer_link_list = undefined;
153
154 $("#dependencies_modal_form").submit(function (e) {
155 e.preventDefault();
156 $("input[name='dependencies']:checked").map(function () { selected.push(parseInt($(this).val()))});
157 layer_link_list = "<a href='"+layerURL+"'>"+layerName+"</a>";
158 if (selected.length > 1) {
159 tooltipUpdateText = "" + selected.length + " layers added";
160 } else {
161 tooltipUpdateText = "1 layer added";
162 }
163
164 for (var i = 0; i < selected.length; i++) {
165 for (var j = 0; j < dependencies.length; j++) {
166 if (dependencies[j].id == selected[i]) {
167 layer_link_list+= ", <a href='"+dependencies[j].layerdetailurl+"'>"+dependencies[j].name+"</a>"
168 break;
169 }
115 } 170 }
171 }
172
173 $('#dependencies_modal').modal('hide');
174
175 {% if project %}
176 _makeXHREditCall({ 'layerAdd': selected.join(",") }, function onXHRSuccess() {
177 show_alert("You have added <strong>"+selected.length+"</strong> layer(s) to <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>:" + layer_link_list);
116 }); 178 });
179 {% endif %}
117 180
118 // enable add target button 181 });
119 $('#add-target-with-deps').removeAttr('disabled'); 182 $('#dependencies_modal').modal('show');
183}
120 184
121 //edit columns functionality (show / hide table columns)
122 $("input:checkbox").change();
123 $("input:checkbox").change(function(){
124 var selectedType = $(this).val();
125 if($(this).is(":checked")){
126 $("."+selectedType).show();
127 }
128 else{
129 $("."+selectedType).hide();
130 }
131 });
132 185
133 //turn edit columns dropdown into a multi-select menu 186var pressedButton = undefined;
134 $('.dropdown-menu input, .dropdown-menu label').click(function(e) {
135 e.stopPropagation();
136 });
137 187
138 //show tooltip with applied filter 188function layerAdd(layerId, layerName, layerURL, pressedButtonId) {
139 $('#filtered').tooltip({container:'table', placement:'bottom', delay:{hide:1500}, html:true}); 189 pressedButton = pressedButtonId;
190 $.ajax({
191 url: '{% url "xhr_datatypeahead" %}',
192 data: {'type': 'layerdeps','value':layerId},
193 success: function(_data) {
194 if (_data.error != "ok") {
195 alert(_data.error);
196 } else {
197 if (_data.list.length > 0) {
198 show_dependencies_modal(layerId, layerName, layerURL, _data.list);
199 }
200 else {
201 tooltipUpdateText = "1 layer added";
202 _makeXHREditCall({ 'layerAdd': layerId }, function () {
203 show_alert("You have added <strong>1</strong> layer to <a href=\"{% url 'project' project.id%}\">{{project.name}}</a>: <a href=\""+layerURL+"\">" + layerName +"</a>");
204 });
205 }
206 }
207 }
208 })
209}
140 210
141 $('#filtered').click(function() { 211function buttonSet(id, state) {
142 $(this).tooltip('hide'); 212 var tohide, toshow;
143 }); 213 if (state == "add")
214 {
215 toshow = "#layer-add-";
216 tohide = "#target-build-";
217 }
218 else if (state == "build")
219 {
220 tohide = "#layer-add-";
221 toshow = "#target-build-";
222 }
144 223
145 //show target added tooltip 224 var previouslyvisible = $(tohide + id).is(":visible");
146 $("#remove-target, #add-target, #add-target-with-deps2").tooltip({ trigger: 'manual' }); 225 if (previouslyvisible && id == pressedButton) {
147 226 $(tohide + id).fadeOut( function() {
148 // add target without dependencies 227 $("#layer-tooltip-" + id).text(tooltipUpdateText);
149 $("#add-target").click(function(){ 228 $("#layer-tooltip-" + id).fadeIn().delay(2000).fadeOut(function(){
150 $('#target-removed').hide(); 229 $(toshow + id).delay(300).fadeIn();
151 $('#target-added').html('<button type="button" class="close" data-dismiss="alert">&times;</button><strong>1</strong> target added to <a href="project-with-targets.html">your project</a>: <a href="#">meta-aarch64</a>').fadeIn();
152 $('#add-target').tooltip('show');
153 $("#add-target").hide();
154 $(".add-targets .tooltip").delay(2000).fadeOut(function(){
155 $("#remove-target").delay(300).fadeIn();
156 }); 230 });
157 }); 231 });
232 } else {
233 $(tohide + id).hide();
234 $("#layer-tooltip-" + id).hide();
235 $(toshow + id).show();
236 }
237};
158 238
159 // add target with dependencies
160 $(document).on("click", "#add-target-dependencies", function() {
161 $('#target-removed').hide();
162 $('#target-added').html('<button type="button" class="close" data-dismiss="alert">&times;</button><strong>3</strong> targets added to <a href="project-with-targets.html">your project</a>: <a href="#">meta-acer</a> and its dependencies <a href="#">meta-android</a> and <a href="#">meta-oe</a>').delay(400).fadeIn(function(){
163 $('#add-target-with-deps').tooltip('show');
164 $("#add-target-with-deps, #add-target-with-deps").hide();
165 $(".add-targets .tooltip").delay(2000).fadeOut(function(){
166 $("#remove-target-with-deps").delay(300).fadeIn();
167 });
168 });
169 });
170 239
171 // delete target 240function updateButtons(projectLayers) {
172 $("#remove-target").click(function(){ 241 var displayedLayers = [];
173 $('#target-added').hide(); 242 $(".add-layer").map(function () { displayedLayers.push( { "l": parseInt($(this).attr('layerversion_id')), "i": parseInt($(this).attr('value'))})});
174 $('#target-removed').show(); 243 for (var i=0; i < displayedLayers.length; i++) {
175 $('#remove-target').tooltip('show'); 244 if (projectLayers.indexOf(displayedLayers[i].l) > -1) {
176 $("#remove-target").hide(); 245 buttonSet(displayedLayers[i].i, "build");
177 $(".add-targets .tooltip").delay(2000).fadeOut(function(){ 246 }
178 $("#add-target").delay(300).fadeIn(); 247 else {
179 }); 248 buttonSet(displayedLayers[i].i, "add");
180 }); 249 }
250 }
251}
181 252
182 }); 253$(document).ready(function (){
254 updateButtons({{projectlayerset}});
255});
183 256
184</script> 257</script>
258{%endif%}
185 259
186{% endblock %} 260{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index e568ee70ed..fb8075067a 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -123,7 +123,7 @@ def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs):
123 params[i] = g[i] 123 params[i] = g[i]
124 for i in mandatory_parameters: 124 for i in mandatory_parameters:
125 if not i in params: 125 if not i in params:
126 params[i] = mandatory_parameters[i] 126 params[i] = urllib.unquote(str(mandatory_parameters[i]))
127 127
128 return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs) 128 return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs)
129 129
@@ -202,6 +202,7 @@ def _get_search_results(search_term, queryset, model):
202 202
203 search_objects.append(reduce(operator.or_, q_map)) 203 search_objects.append(reduce(operator.or_, q_map))
204 search_object = reduce(operator.and_, search_objects) 204 search_object = reduce(operator.and_, search_objects)
205 print "search objects", search_object
205 queryset = queryset.filter(search_object) 206 queryset = queryset.filter(search_object)
206 207
207 return queryset 208 return queryset
@@ -1914,8 +1915,7 @@ if toastermain.settings.MANAGED:
1914 login(request, user) 1915 login(request, user)
1915 1916
1916 # save the project 1917 # save the project
1917 prj = Project.objects.create_project(name = request.POST['projectname'], 1918 prj = Project.objects.create_project(name = request.POST['projectname'], release = Release.objects.get(pk = request.POST['projectversion']))
1918 release = Release.objects.get(pk = request.POST['projectversion']))
1919 prj.user_id = request.user.pk 1919 prj.user_id = request.user.pk
1920 prj.save() 1920 prj.save()
1921 return redirect(reverse(project, args = (prj.pk,)) + "#/newproject") 1921 return redirect(reverse(project, args = (prj.pk,)) + "#/newproject")
@@ -1933,36 +1933,21 @@ if toastermain.settings.MANAGED:
1933 1933
1934 1934
1935 def _project_recent_build_list(prj): 1935 def _project_recent_build_list(prj):
1936 # build requests not yet started 1936 return map(lambda x: {
1937 return (map(lambda x: {
1938 "id": x.pk,
1939 "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
1940 "status": x.get_state_display(),
1941 }, prj.buildrequest_set.filter(state__lt = BuildRequest.REQ_INPROGRESS).order_by("-pk")) +
1942 # build requests started, but with no build yet
1943 map(lambda x: {
1944 "id": x.pk, 1937 "id": x.pk,
1945 "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()), 1938 "targets" : map(lambda y: {"target": y.target, "task": y.task }, x.brtarget_set.all()),
1946 "status": x.get_state_display(),
1947 }, prj.buildrequest_set.filter(state = BuildRequest.REQ_INPROGRESS, build = None).order_by("-pk")) +
1948 # build requests that failed
1949 map(lambda x: {
1950 "id": x.pk,
1951 "targets" : map(lambda y: {"target": y.target }, x.brtarget_set.all()),
1952 "status": x.get_state_display(), 1939 "status": x.get_state_display(),
1953 "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()), 1940 "errors": map(lambda y: {"type": y.errtype, "msg": y.errmsg, "tb": y.traceback}, x.brerror_set.all()),
1954 }, prj.buildrequest_set.filter(state = BuildRequest.REQ_FAILED).order_by("-pk")) + 1941 "build" : map( lambda y: {"id": y.pk,
1955 # and already made builds 1942 "status": y.get_outcome_display(),
1956 map(lambda x: { 1943 "completed_on" : y.completed_on.strftime('%s')+"000",
1957 "id": x.pk, 1944 "build_time" : (y.completed_on - y.started_on).total_seconds(),
1958 "targets": map(lambda y: {"target": y.target }, x.target_set.all()), 1945 "build_page_url" : reverse('builddashboard', args=(y.pk,)),
1959 "status": x.get_outcome_display(), 1946 "errors": y.errors_no,
1960 "completed_on" : x.completed_on.strftime('%s')+"000", 1947 "warnings": y.warnings_no,
1961 "build_time" : (x.completed_on - x.started_on).total_seconds(), 1948 "completeper": y.completeper(),
1962 "build_page_url" : reverse('builddashboard', args=(x.pk,)), 1949 "eta": y.eta().ctime()}, Build.objects.filter(buildrequest = x)),
1963 "completeper": x.completeper(), 1950 }, prj.buildrequest_set.order_by("-pk")[:5])
1964 "eta": x.eta().ctime(),
1965 }, prj.build_set.all()))
1966 1951
1967 1952
1968 # Shows the edit project page 1953 # Shows the edit project page
@@ -2025,10 +2010,14 @@ if toastermain.settings.MANAGED:
2025 2010
2026 if 'buildCancel' in request.POST: 2011 if 'buildCancel' in request.POST:
2027 for i in request.POST['buildCancel'].strip().split(" "): 2012 for i in request.POST['buildCancel'].strip().split(" "):
2028 br = BuildRequest.objects.select_for_update().get(project = prj, pk = i, state__lte = BuildRequest.REQ_QUEUED) 2013 try:
2029 print "selected for delete", br.pk 2014 br = BuildRequest.objects.select_for_update().get(project = prj, pk = i, state__lte = BuildRequest.REQ_QUEUED)
2030 br.delete() 2015 print "selected for delete", br.pk
2031 print "selected for delete", br.pk 2016 br.delete()
2017 print "selected for delete", br.pk
2018 except BuildRequest.DoesNotExist:
2019 pass
2020
2032 2021
2033 if 'targets' in request.POST: 2022 if 'targets' in request.POST:
2034 ProjectTarget.objects.filter(project = prj).delete() 2023 ProjectTarget.objects.filter(project = prj).delete()
@@ -2059,7 +2048,7 @@ if toastermain.settings.MANAGED:
2059 # remove layers 2048 # remove layers
2060 if 'layerDel' in request.POST: 2049 if 'layerDel' in request.POST:
2061 for t in request.POST['layerDel'].strip().split(" "): 2050 for t in request.POST['layerDel'].strip().split(" "):
2062 pt = ProjectLayer.objects.get(project = prj, layercommit_id = int(t)).delete() 2051 pt = ProjectLayer.objects.filter(project = prj, layercommit_id = int(t)).delete()
2063 2052
2064 if 'projectName' in request.POST: 2053 if 'projectName' in request.POST:
2065 prj.name = request.POST['projectName'] 2054 prj.name = request.POST['projectName']
@@ -2071,8 +2060,8 @@ if toastermain.settings.MANAGED:
2071 prj.save() 2060 prj.save()
2072 # we need to change the layers 2061 # we need to change the layers
2073 for i in prj.projectlayer_set.all(): 2062 for i in prj.projectlayer_set.all():
2074 # find and add a similarly-named layer from the same layer source on the new branch 2063 # find and add a similarly-named layer on the new branch
2075 lv = Layer_Version.objects.filter(layer_source = i.layercommit.layer_source, layer__name = i.layercommit.layer.name, up_branch__in = Branch.objects.filter(name = prj.release.branch)) 2064 lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__release = prj.release)
2076 if lv.count() == 1: 2065 if lv.count() == 1:
2077 ProjectLayer.objects.get_or_create(project = prj, layercommit = lv[0]) 2066 ProjectLayer.objects.get_or_create(project = prj, layercommit = lv[0])
2078 # get rid of the old entry 2067 # get rid of the old entry
@@ -2095,17 +2084,19 @@ if toastermain.settings.MANAGED:
2095 @csrf_exempt 2084 @csrf_exempt
2096 def xhr_datatypeahead(request): 2085 def xhr_datatypeahead(request):
2097 try: 2086 try:
2087 # returns layers for current project release that are not in the project set
2098 if request.GET['type'] == "layers": 2088 if request.GET['type'] == "layers":
2099 queryset_all = Layer_Version.objects.all() 2089 queryset_all = Layer_Version.objects.all()
2100 if 'project_id' in request.session: 2090 if 'project_id' in request.session:
2101 prj = Project.objects.get(pk = request.session['project_id']) 2091 prj = Project.objects.get(pk = request.session['project_id'])
2102 queryset_all = queryset_all.filter(up_branch__in = Branch.objects.filter(name = prj.release.name)).exclude(pk__in = map(lambda x: x.layercommit_id, prj.projectlayer_set.all())) 2092 queryset_all = queryset_all.filter(up_branch__release = prj.release).exclude(pk__in = map(lambda x: x.layercommit_id, prj.projectlayer_set.all()))
2103 queryset_all = queryset_all.filter(layer__name__icontains=request.GET.get('value','')) 2093 queryset_all = queryset_all.filter(layer__name__icontains=request.GET.get('value',''))
2104 return HttpResponse(json.dumps( { "error":"ok", 2094 return HttpResponse(json.dumps( { "error":"ok",
2105 "list" : map( lambda x: {"id": x.pk, "name": x.layer.name, "detail": "(" + x.layer.layer_source.name + (")" if x.up_branch == None else " | "+x.up_branch.name+")")}, 2095 "list" : map( lambda x: {"id": x.pk, "name": x.layer.name, "detail": "(" + x.layer.layer_source.name + (")" if x.up_branch == None else " | "+x.up_branch.name+")")},
2106 queryset_all[:8]) 2096 queryset_all[:8])
2107 }), content_type = "application/json") 2097 }), content_type = "application/json")
2108 2098
2099 # returns layer dependencies for a layer, excluding current project layers
2109 if request.GET['type'] == "layerdeps": 2100 if request.GET['type'] == "layerdeps":
2110 queryset_all = LayerVersionDependency.objects.filter(layer_version_id = request.GET['value']) 2101 queryset_all = LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])
2111 2102
@@ -2122,6 +2113,7 @@ if toastermain.settings.MANAGED:
2122 map(lambda x: x.depends_on, queryset_all)) 2113 map(lambda x: x.depends_on, queryset_all))
2123 }), content_type = "application/json") 2114 }), content_type = "application/json")
2124 2115
2116 # returns layer versions that would be deleted on the new release__pk
2125 if request.GET['type'] == "versionlayers": 2117 if request.GET['type'] == "versionlayers":
2126 if not 'project_id' in request.session: 2118 if not 'project_id' in request.session:
2127 raise Exception("This call cannot makes no sense outside a project context") 2119 raise Exception("This call cannot makes no sense outside a project context")
@@ -2129,8 +2121,8 @@ if toastermain.settings.MANAGED:
2129 retval = [] 2121 retval = []
2130 prj = Project.objects.get(pk = request.session['project_id']) 2122 prj = Project.objects.get(pk = request.session['project_id'])
2131 for i in prj.projectlayer_set.all(): 2123 for i in prj.projectlayer_set.all():
2132 lv = Layer_Version.objects.filter(layer_source = i.layercommit.layer_source, layer__name = i.layercommit.layer.name, up_branch__in = Branch.objects.filter(name = Release.objects.get(pk=request.GET['value']).branch)) 2124 lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__release__pk=request.GET['value'])
2133 if lv.count() != 1: 2125 if lv.count() != 1: # there is no layer_version with the new release id, and the same name
2134 retval.append(i) 2126 retval.append(i)
2135 2127
2136 return HttpResponse(json.dumps( {"error":"ok", 2128 return HttpResponse(json.dumps( {"error":"ok",
@@ -2138,14 +2130,14 @@ if toastermain.settings.MANAGED:
2138 lambda x: {"id": x.layercommit.pk, "name": x.layercommit.layer.name, "detail": "(" + x.layercommit.layer.layer_source.name + (")" if x.layercommit.up_branch == None else " | "+x.layercommit.up_branch.name+")")}, 2130 lambda x: {"id": x.layercommit.pk, "name": x.layercommit.layer.name, "detail": "(" + x.layercommit.layer.layer_source.name + (")" if x.layercommit.up_branch == None else " | "+x.layercommit.up_branch.name+")")},
2139 retval) }), content_type = "application/json") 2131 retval) }), content_type = "application/json")
2140 2132
2141 2133 # returns targets provided by current project layers
2142 if request.GET['type'] == "targets": 2134 if request.GET['type'] == "targets":
2143 queryset_all = Recipe.objects.all() 2135 queryset_all = Recipe.objects.all()
2144 if 'project_id' in request.session: 2136 if 'project_id' in request.session:
2145 queryset_all = queryset_all.filter(layer_version__layer__in = map(lambda x: x.layercommit.layer, ProjectLayer.objects.filter(project_id=request.session['project_id']))) 2137 queryset_all = queryset_all.filter(layer_version__layer__in = map(lambda x: x.layercommit.layer, ProjectLayer.objects.filter(project_id=request.session['project_id'])))
2146 return HttpResponse(json.dumps({ "error":"ok", 2138 return HttpResponse(json.dumps({ "error":"ok",
2147 "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 "]")}, 2139 "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 "]")},
2148 queryset_all.filter(name__istartswith=request.GET.get('value',''))[:8]), 2140 queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]),
2149 2141
2150 }), content_type = "application/json") 2142 }), content_type = "application/json")
2151 2143
@@ -2155,7 +2147,7 @@ if toastermain.settings.MANAGED:
2155 queryset_all = queryset_all.filter(layer_version__layer__in = map(lambda x: x.layercommit.layer, ProjectLayer.objects.filter(project_id=request.session['project_id']))) 2147 queryset_all = queryset_all.filter(layer_version__layer__in = map(lambda x: x.layercommit.layer, ProjectLayer.objects.filter(project_id=request.session['project_id'])))
2156 return HttpResponse(json.dumps({ "error":"ok", 2148 return HttpResponse(json.dumps({ "error":"ok",
2157 "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 "]")}, 2149 "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 "]")},
2158 queryset_all.filter(name__istartswith=request.GET.get('value',''))[:8]), 2150 queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]),
2159 2151
2160 }), content_type = "application/json") 2152 }), content_type = "application/json")
2161 2153
@@ -2173,11 +2165,15 @@ if toastermain.settings.MANAGED:
2173 2165
2174 2166
2175 def layers(request): 2167 def layers(request):
2168 if not 'project_id' in request.session:
2169 raise Exception("invalid page: cannot show page without a project")
2170
2176 template = "layers.html" 2171 template = "layers.html"
2177 # define here what parameters the view needs in the GET portion in order to 2172 # define here what parameters the view needs in the GET portion in order to
2178 # be able to display something. 'count' and 'page' are mandatory for all views 2173 # be able to display something. 'count' and 'page' are mandatory for all views
2179 # that use paginators. 2174 # that use paginators.
2180 mandatory_parameters = { 'count': 10, 'page' : 1, 'orderby' : 'layer__name:+' }; 2175 (pagesize, orderby) = _get_parameters_values(request, 100, 'layer__name:+')
2176 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby };
2181 retval = _verify_parameters( request.GET, mandatory_parameters ) 2177 retval = _verify_parameters( request.GET, mandatory_parameters )
2182 if retval: 2178 if retval:
2183 return _redirect_parameters( 'layers', request.GET, mandatory_parameters) 2179 return _redirect_parameters( 'layers', request.GET, mandatory_parameters)
@@ -2187,18 +2183,9 @@ if toastermain.settings.MANAGED:
2187 (filter_string, search_term, ordering_string) = _search_tuple(request, Layer_Version) 2183 (filter_string, search_term, ordering_string) = _search_tuple(request, Layer_Version)
2188 2184
2189 queryset_all = Layer_Version.objects.all() 2185 queryset_all = Layer_Version.objects.all()
2190 # mock an empty Project if we are outside project context
2191 class _mockProject(object):
2192 id = -1
2193 class _mockManager(object):
2194 def all(self):
2195 return []
2196 projectlayer_set = _mockManager()
2197 prj = _mockProject()
2198 2186
2199 if 'project_id' in request.session: 2187 prj = Project.objects.get(pk = request.session['project_id'])
2200 prj = Project.objects.get(pk = request.session['project_id']) 2188 queryset_all = queryset_all.filter(up_branch__release = prj.release)
2201 queryset_all = queryset_all.filter(up_branch__in = Branch.objects.filter(name = prj.release.name))
2202 2189
2203 queryset_with_search = _get_queryset(Layer_Version, queryset_all, None, search_term, ordering_string, '-layer__name') 2190 queryset_with_search = _get_queryset(Layer_Version, queryset_all, None, search_term, ordering_string, '-layer__name')
2204 queryset = _get_queryset(Layer_Version, queryset_all, filter_string, search_term, ordering_string, '-layer__name') 2191 queryset = _get_queryset(Layer_Version, queryset_all, filter_string, search_term, ordering_string, '-layer__name')
@@ -2265,7 +2252,6 @@ if toastermain.settings.MANAGED:
2265 2252
2266 } 2253 }
2267 }, 2254 },
2268
2269 ] 2255 ]
2270 } 2256 }
2271 2257
@@ -2279,31 +2265,30 @@ if toastermain.settings.MANAGED:
2279 return render(request, template, context) 2265 return render(request, template, context)
2280 2266
2281 def targets(request): 2267 def targets(request):
2282 template = "targets.html" 2268 if not 'project_id' in request.session:
2283 # define here what parameters the view needs in the GET portion in order to 2269 raise Exception("invalid page: cannot show page without a project")
2284 # be able to display something. 'count' and 'page' are mandatory for all views 2270
2285 # that use paginators. 2271 template = 'targets.html'
2286 mandatory_parameters = { 'count': 10, 'page' : 1, 'orderby' : 'name:+' }; 2272 (pagesize, orderby) = _get_parameters_values(request, 100, 'name:+')
2273 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
2287 retval = _verify_parameters( request.GET, mandatory_parameters ) 2274 retval = _verify_parameters( request.GET, mandatory_parameters )
2288 if retval: 2275 if retval:
2289 return _redirect_parameters( 'targets', request.GET, mandatory_parameters) 2276 return _redirect_parameters( 'targets', request.GET, mandatory_parameters)
2290
2291 # boilerplate code that takes a request for an object type and returns a queryset
2292 # for that object type. copypasta for all needed table searches
2293 (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe) 2277 (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe)
2294 2278
2295 queryset_all = Recipe.objects.all() 2279 prj = Project.objects.get(pk = request.session['project_id'])
2296 if 'project_id' in request.session: 2280 queryset_all = Recipe.objects.filter(Q(layer_version__up_branch__release = prj.release) | Q(layer_version__build__in = prj.build_set.all()))
2297 queryset_all = queryset_all.filter(Q(layer_version__up_branch__in = Branch.objects.filter(name = Project.objects.get(pk=request.session['project_id']).release.name)) | Q(layer_version__build__in = Project.objects.get(pk = request.session['project_id']).build_set.all()))
2298 2281
2299 queryset_with_search = _get_queryset(Recipe, queryset_all, None, search_term, ordering_string, '-name') 2282 queryset_with_search = _get_queryset(Recipe, queryset_all, None, search_term, ordering_string, '-name')
2300 queryset = _get_queryset(Recipe, queryset_all, filter_string, search_term, ordering_string, '-name') 2283
2284 queryset_with_search.prefetch_related("layer_source")
2301 2285
2302 # retrieve the objects that will be displayed in the table; targets a paginator and gets a page range to display 2286 # retrieve the objects that will be displayed in the table; targets a paginator and gets a page range to display
2303 target_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1)) 2287 target_info = _build_page_range(Paginator(queryset_with_search, request.GET.get('count', 10)),request.GET.get('page', 1))
2304 2288
2305 2289
2306 context = { 2290 context = {
2291 'projectlayerset' : json.dumps(map(lambda x: x.layercommit.id, prj.projectlayer_set.all())),
2307 'objects' : target_info, 2292 'objects' : target_info,
2308 'objectname' : "targets", 2293 'objectname' : "targets",
2309 'default_orderby' : 'name:+', 2294 'default_orderby' : 'name:+',
@@ -2329,13 +2314,19 @@ if toastermain.settings.MANAGED:
2329 { 'name': 'Section', 2314 { 'name': 'Section',
2330 'clclass': 'target-section', 2315 'clclass': 'target-section',
2331 'hidden': 1, 2316 'hidden': 1,
2317 'orderfield': _get_toggle_order(request, "section"),
2318 'ordericon': _get_toggle_order_icon(request, "section"),
2332 }, 2319 },
2333 { 'name': 'License', 2320 { 'name': 'License',
2334 'clclass': 'license', 2321 'clclass': 'license',
2335 'hidden': 1, 2322 'hidden': 1,
2323 'orderfield': _get_toggle_order(request, "license"),
2324 'ordericon': _get_toggle_order_icon(request, "license"),
2336 }, 2325 },
2337 { 'name': 'Layer', 2326 { 'name': 'Layer',
2338 'clclass': 'layer', 2327 'clclass': 'layer',
2328 'orderfield': _get_toggle_order(request, "layer_version__layer__name"),
2329 'ordericon': _get_toggle_order_icon(request, "layer_version__layer__name"),
2339 }, 2330 },
2340 { 'name': 'Layer source', 2331 { 'name': 'Layer source',
2341 'clclass': 'source', 2332 'clclass': 'source',
@@ -2345,20 +2336,32 @@ if toastermain.settings.MANAGED:
2345 'filter': { 2336 'filter': {
2346 'class': 'target', 2337 'class': 'target',
2347 'label': 'Show:', 2338 'label': 'Show:',
2348 'options': map(lambda x: (x.name, 'layer_source__pk:' + str(x.id), queryset_with_search.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()), 2339 'options': map(lambda x: ("Targets provided by " + x.name + " layers", 'layer_source__pk:' + str(x.id), queryset_with_search.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()),
2349 } 2340 }
2350 }, 2341 },
2351 { 'name': 'Branch, tag or commit', 2342 { 'name': 'Branch, tag or commit',
2352 'clclass': 'branch', 2343 'clclass': 'branch',
2353 'hidden': 1, 2344 'hidden': 1,
2354 }, 2345 },
2346 ]
2347 }
2348
2349 if 'project_id' in request.session:
2350 context['tablecols'] += [
2355 { 'name': 'Build', 2351 { 'name': 'Build',
2356 'dclass': 'span2', 2352 'dclass': 'span2',
2357 'qhelp': "Add or delete targets to / from your project ", 2353 'qhelp': "Add or delete targets to / from your project ",
2358 }, 2354 'filter': {
2355 'class': 'add-layer',
2356 'label': 'Show:',
2357 'options': [
2358 ('Targets provided by layers added to this project', "layer_version__projectlayer__project:" + str(prj.id), queryset_with_search.filter(layer_version__projectlayer__project = prj.id).count()),
2359 ('Targets provided by layers not added to this project', "layer_version__projectlayer__project:NOT" + str(prj.id), queryset_with_search.exclude(layer_version__projectlayer__project = prj.id).count()),
2360 ]
2361
2362 }
2363 }, ]
2359 2364
2360 ]
2361 }
2362 2365
2363 return render(request, template, context) 2366 return render(request, template, context)
2364 2367
@@ -2378,7 +2381,7 @@ if toastermain.settings.MANAGED:
2378 2381
2379 queryset_all = Machine.objects.all() 2382 queryset_all = Machine.objects.all()
2380# if 'project_id' in request.session: 2383# if 'project_id' in request.session:
2381# queryset_all = queryset_all.filter(Q(layer_version__up_branch__in = Branch.objects.filter(name = Project.objects.get(request.session['project_id']).release.name)) | Q(layer_version__build__in = Project.objects.get(request.session['project_id']).build_set.all())) 2384# queryset_all = queryset_all.filter(Q(layer_version__up_branch__release = Project.objects.get(request.session['project_id']).release) | Q(layer_version__build__in = Project.objects.get(request.session['project_id']).build_set.all()))
2382 2385
2383 queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name') 2386 queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
2384 queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name') 2387 queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name')
@@ -2643,7 +2646,7 @@ if toastermain.settings.MANAGED:
2643 def projects(request): 2646 def projects(request):
2644 template="projects.html" 2647 template="projects.html"
2645 2648
2646 (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-') 2649 (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:+')
2647 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } 2650 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
2648 retval = _verify_parameters( request.GET, mandatory_parameters ) 2651 retval = _verify_parameters( request.GET, mandatory_parameters )
2649 if retval: 2652 if retval:
@@ -2654,8 +2657,8 @@ if toastermain.settings.MANAGED:
2654 # boilerplate code that takes a request for an object type and returns a queryset 2657 # boilerplate code that takes a request for an object type and returns a queryset
2655 # for that object type. copypasta for all needed table searches 2658 # for that object type. copypasta for all needed table searches
2656 (filter_string, search_term, ordering_string) = _search_tuple(request, Project) 2659 (filter_string, search_term, ordering_string) = _search_tuple(request, Project)
2657 queryset_with_search = _get_queryset(Project, queryset_all, None, search_term, ordering_string, 'updated:-') 2660 queryset_with_search = _get_queryset(Project, queryset_all, None, search_term, ordering_string, '-updated')
2658 queryset = _get_queryset(Project, queryset_all, filter_string, search_term, ordering_string, 'updated:-') 2661 queryset = _get_queryset(Project, queryset_all, filter_string, search_term, ordering_string, '-updated')
2659 2662
2660 # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display 2663 # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display
2661 project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) 2664 project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1))