diff options
author | Alexandru DAMIAN <alexandru.damian@intel.com> | 2014-10-02 17:58:15 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2014-11-12 17:04:48 +0000 |
commit | 42afeb422ea0a5e226cef586353d194d0339bbd7 (patch) | |
tree | 86bc1c6716b6b60bb4f77ebd9fa9d044da0daf7a /bitbake | |
parent | 46f1fbe3abb3677861178b7008bf5edf73125197 (diff) | |
download | poky-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>
Diffstat (limited to 'bitbake')
-rw-r--r-- | bitbake/lib/toaster/bldcontrol/models.py | 33 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/static/css/default.css | 4 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/projectapp.js | 24 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/base.html | 3 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/basetable_bottom.html | 13 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/layers.html | 124 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/mrb_section.html | 11 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/project.html | 48 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/templates/targets.html | 340 | ||||
-rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 157 |
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 */ |
63 | td a, td a > code { color: #333333; } | 63 | td a, td a > code { color: #333333; } |
64 | td a > code { white-space: normal; } | 64 | td code { white-space: normal; } |
65 | td a:hover { color: #000000; text-decoration: underline; } | 65 | td 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 | ||
97 | projectApp.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 |
96 | projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $location, $cookies, $q, $sce) { | 114 | projectApp.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 | ||
100 | var tooltipUpdateText; | ||
101 | |||
100 | function _makeXHREditCall(data, onsuccess, onfail) { | 102 | function _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 | ||
122 | function layerDel(layerId, layerName, layerURL) { | 124 | function 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 | ||
128 | function show_alert(text, cls) { | 131 | function show_alert(text, cls) { |
129 | $("#zone1alerts").html("<div class=\"alert alert-info\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button>" + text + "</div>"); | 132 | $("#zone1alerts").html("<div class=\"alert alert-info lead\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button>" + text + "</div>"); |
130 | } | 133 | } |
131 | 134 | ||
132 | function show_dependencies_modal(layerId, layerName, layerURL, dependencies) { | 135 | function 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 | ||
190 | function button_set(id, state) { | 204 | function 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 | ||
89 | function scheduleBuild(url, projectName, buildlist) { | 88 | function 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">×</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> | 110 | var tooltipUpdateText; |
102 | <script src="assets/js/main.js" type='text/javascript'></script> | 111 | |
103 | 112 | function _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 | |||
133 | function show_alert(text, cls) { | ||
134 | $("#zone1alerts").html("<div class=\"alert alert-info lead\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button>" + text + "</div>"); | ||
135 | } | ||
136 | |||
137 | |||
138 | function 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 | 186 | var pressedButton = undefined; |
134 | $('.dropdown-menu input, .dropdown-menu label').click(function(e) { | ||
135 | e.stopPropagation(); | ||
136 | }); | ||
137 | 187 | ||
138 | //show tooltip with applied filter | 188 | function 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() { | 211 | function 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">×</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">×</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 | 240 | function 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)) |