summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui
diff options
context:
space:
mode:
authorMichael Wood <michael.g.wood@intel.com>2015-05-18 20:08:28 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-05-29 11:59:45 +0100
commit2de01a68eb6a9ca74384957c674928944c235269 (patch)
tree7dbe5a8a2a169dac697bed032263c624e9c2be7e /bitbake/lib/toaster/toastergui
parenta0ea663b83ecf5f286844420b071101feefc3d22 (diff)
downloadpoky-2de01a68eb6a9ca74384957c674928944c235269.tar.gz
bitbake: toaster: Port layerdetails to ToasterTables
This ports the layerdetails page to using ToasterTables Also some whitespace and strict clean ups in the existing layerdetails js and html template. (Bitbake rev: 8ce35f81631e31539aeb82f8a85abbb3312e5097) Signed-off-by: Michael Wood <michael.g.wood@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastergui')
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/layerdetails.js70
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/libtoaster.js3
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/table.js77
-rw-r--r--bitbake/lib/toaster/toastergui/tables.py87
-rw-r--r--bitbake/lib/toaster/toastergui/templates/layerdetails.html594
-rw-r--r--bitbake/lib/toaster/toastergui/templates/toastertable-filter.html18
-rw-r--r--bitbake/lib/toaster/toastergui/templates/toastertable-simple.html26
-rw-r--r--bitbake/lib/toaster/toastergui/templates/toastertable.html50
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py6
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py49
-rw-r--r--bitbake/lib/toaster/toastergui/widgets.py17
11 files changed, 415 insertions, 582 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/layerdetails.js b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js
index 3c4d632563..3746ea26e3 100644
--- a/bitbake/lib/toaster/toastergui/static/js/layerdetails.js
+++ b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js
@@ -1,4 +1,4 @@
1"use strict" 1"use strict";
2 2
3function layerDetailsPageInit (ctx) { 3function layerDetailsPageInit (ctx) {
4 4
@@ -54,7 +54,7 @@ function layerDetailsPageInit (ctx) {
54 54
55 /* Add dependency layer button click handler */ 55 /* Add dependency layer button click handler */
56 layerDepBtn.click(function(){ 56 layerDepBtn.click(function(){
57 if (currentLayerDepSelection == undefined) 57 if (currentLayerDepSelection === undefined)
58 return; 58 return;
59 59
60 addRemoveDep(currentLayerDepSelection.id, true, function(){ 60 addRemoveDep(currentLayerDepSelection.id, true, function(){
@@ -122,13 +122,6 @@ function layerDetailsPageInit (ctx) {
122 }); 122 });
123 }); 123 });
124 124
125 $(".build-target-btn").click(function(){
126 /* fire a build */
127 var target = $(this).data('target-name');
128 libtoaster.startABuild(ctx.projectBuildUrl, libtoaster.ctx.projectId, target, null, null);
129 window.location.replace(libtoaster.ctx.projectPageUrl);
130 });
131
132 function defaultAddBtnText(){ 125 function defaultAddBtnText(){
133 var text = " Add the "+ctx.layerVersion.name+" layer to your project"; 126 var text = " Add the "+ctx.layerVersion.name+" layer to your project";
134 addRmLayerBtn.text(text); 127 addRmLayerBtn.text(text);
@@ -155,9 +148,48 @@ function layerDetailsPageInit (ctx) {
155 } 148 }
156 } 149 }
157 150
158 window.location.hash = "targets"; 151 window.location.hash = "recipes";
159 } 152 }
160 153
154 $("#recipestable").on('table-done', function(e, total, tableParams){
155 ctx.numTargets = total;
156
157 if (total === 0 && !tableParams.search) {
158 $("#no-recipes-yet").show();
159 } else {
160 $("#no-recipes-yet").hide();
161 }
162
163 $("#targets-tab").removeClass("muted");
164 if (window.location.hash === "#recipes"){
165 /* re run the machinesTabShow to update the text */
166 targetsTabShow();
167 }
168
169 $(".build-target-btn").unbind('click');
170 $(".build-target-btn").click(function(){
171 /* fire a build */
172 var target = $(this).data('target-name');
173 libtoaster.startABuild(ctx.projectBuildUrl, libtoaster.ctx.projectId, target, null, null);
174 window.location.replace(libtoaster.ctx.projectPageUrl);
175 });
176 });
177
178 $("#machinestable").on('table-done', function(e, total, tableParams){
179 ctx.numMachines = total;
180
181 if (total === 0 && !tableParams.search)
182 $("#no-machines-yet").show();
183 else
184 $("#no-machines-yet").hide();
185
186 $("#machines-tab").removeClass("muted");
187 if (window.location.hash === "#machines"){
188 /* re run the machinesTabShow to update the text */
189 machinesTabShow();
190 }
191 });
192
161 $("#targets-tab").on('show', targetsTabShow); 193 $("#targets-tab").on('show', targetsTabShow);
162 194
163 function machinesTabShow(){ 195 function machinesTabShow(){
@@ -187,7 +219,7 @@ function layerDetailsPageInit (ctx) {
187 /* Enables the Build target and Select Machine buttons and switches the 219 /* Enables the Build target and Select Machine buttons and switches the
188 * add/remove button 220 * add/remove button
189 */ 221 */
190 function setLayerInCurrentPrj(added, depsList) { 222 function setLayerInCurrentPrj(added) {
191 ctx.layerVersion.inCurrentPrj = added; 223 ctx.layerVersion.inCurrentPrj = added;
192 224
193 if (added){ 225 if (added){
@@ -224,18 +256,20 @@ function layerDetailsPageInit (ctx) {
224 } 256 }
225 } 257 }
226 258
227 $("#dismiss-alert").click(function(){ $(this).parent().hide() }); 259 $("#dismiss-alert").click(function(){
260 $(this).parent().fadeOut();
261 });
228 262
229 /* Add or remove this layer from the project */ 263 /* Add or remove this layer from the project */
230 addRmLayerBtn.click(function() { 264 addRmLayerBtn.click(function() {
231 265
232 var add = ($(this).data('directive') === "add") 266 var add = ($(this).data('directive') === "add");
233 267
234 libtoaster.addRmLayer(ctx.layerVersion, add, function (layersList){ 268 libtoaster.addRmLayer(ctx.layerVersion, add, function (layersList){
235 var alertMsg = $("#alert-msg"); 269 var alertMsg = $("#alert-msg");
236 alertMsg.html(libtoaster.makeLayerAddRmAlertMsg(ctx.layerVersion, layersList, add)); 270 alertMsg.html(libtoaster.makeLayerAddRmAlertMsg(ctx.layerVersion, layersList, add));
237 271
238 setLayerInCurrentPrj(add, layersList); 272 setLayerInCurrentPrj(add);
239 273
240 $("#alert-area").show(); 274 $("#alert-area").show();
241 }); 275 });
@@ -250,9 +284,9 @@ function layerDetailsPageInit (ctx) {
250 * from. 284 * from.
251 */ 285 */
252 var entryElement = mParent.find("input"); 286 var entryElement = mParent.find("input");
253 if (entryElement.length == 0) 287 if (entryElement.length === 0)
254 entryElement = mParent.find("textarea"); 288 entryElement = mParent.find("textarea");
255 if (entryElement.length == 0) { 289 if (entryElement.length === 0) {
256 console.warn("Could not find element to get data from for this change"); 290 console.warn("Could not find element to get data from for this change");
257 return; 291 return;
258 } 292 }
@@ -293,7 +327,7 @@ function layerDetailsPageInit (ctx) {
293 327
294 /* Disable the change button when we have no data in the input */ 328 /* Disable the change button when we have no data in the input */
295 $("dl input, dl textarea").on("input",function() { 329 $("dl input, dl textarea").on("input",function() {
296 if ($(this).val().length == 0) 330 if ($(this).val().length === 0)
297 $(this).parent().children(".change-btn").attr("disabled", "disabled"); 331 $(this).parent().children(".change-btn").attr("disabled", "disabled");
298 else 332 else
299 $(this).parent().children(".change-btn").removeAttr("disabled"); 333 $(this).parent().children(".change-btn").removeAttr("disabled");
@@ -322,7 +356,7 @@ function layerDetailsPageInit (ctx) {
322 }); 356 });
323 357
324 /* Hide the right column if it contains no information */ 358 /* Hide the right column if it contains no information */
325 if ($("dl.item-info").children(':visible').length == 0) { 359 if ($("dl.item-info").children(':visible').length === 0) {
326 $("dl.item-info").parent().hide(); 360 $("dl.item-info").parent().hide();
327 } 361 }
328 362
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
index 1ac26d4c7f..99e1f03095 100644
--- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
+++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
@@ -216,6 +216,9 @@ var libtoaster = (function (){
216 str += "&"; 216 str += "&";
217 } 217 }
218 218
219 /* Maintain the current hash */
220 str += window.location.hash;
221
219 return str; 222 return str;
220 } 223 }
221 224
diff --git a/bitbake/lib/toaster/toastergui/static/js/table.js b/bitbake/lib/toaster/toastergui/static/js/table.js
index 97370fd020..2e35e3871c 100644
--- a/bitbake/lib/toaster/toastergui/static/js/table.js
+++ b/bitbake/lib/toaster/toastergui/static/js/table.js
@@ -64,10 +64,12 @@ function tableInit(ctx){
64 64
65 function updateTable(tableData) { 65 function updateTable(tableData) {
66 var tableBody = table.children("tbody"); 66 var tableBody = table.children("tbody");
67 var paginationBtns = $('#pagination-'+ctx.tableName); 67 var pagination = $('#pagination-'+ctx.tableName);
68 var paginationBtns = pagination.children('ul');
69 var tableContainer = $("#table-container-"+ctx.tableName);
68 70
71 tableContainer.css("visibility", "hidden");
69 /* To avoid page re-layout flicker when paging set fixed height */ 72 /* To avoid page re-layout flicker when paging set fixed height */
70 table.css("visibility", "hidden");
71 table.css("padding-bottom", table.height()); 73 table.css("padding-bottom", table.height());
72 74
73 /* Reset table components */ 75 /* Reset table components */
@@ -83,19 +85,30 @@ function tableInit(ctx){
83 tableTotal = tableData.total; 85 tableTotal = tableData.total;
84 86
85 if (tableData.total === 0){ 87 if (tableData.total === 0){
86 $("#table-container-"+ctx.tableName).hide(); 88 tableContainer.hide();
87 $("#new-search-input-"+ctx.tableName).val(tableParams.search); 89 /* If we were searching show the new search bar and return */
88 $("#no-results-"+ctx.tableName).show(); 90 if (tableParams.search){
91 $("#new-search-input-"+ctx.tableName).val(tableParams.search);
92 $("#no-results-"+ctx.tableName).show();
93 }
94 table.trigger("table-done", [tableData.total, tableParams]);
95
89 return; 96 return;
97
98 /* We don't want to clutter the place with the table chrome if there
99 * are only a few results */
100 } else if (tableData.total <= 10 &&
101 !tableParams.filter &&
102 !tableParams.search){
103 $("#table-chrome-"+ctx.tableName).hide();
104 pagination.hide();
90 } else { 105 } else {
91 $("#table-container-"+ctx.tableName).show(); 106 tableContainer.show();
92 $("#no-results-"+ctx.tableName).hide(); 107 $("#no-results-"+ctx.tableName).hide();
93 } 108 }
94 109
95
96 setupTableChrome(tableData); 110 setupTableChrome(tableData);
97 111
98
99 /* Add table data rows */ 112 /* Add table data rows */
100 for (var i in tableData.rows){ 113 for (var i in tableData.rows){
101 var row = $("<tr></tr>"); 114 var row = $("<tr></tr>");
@@ -137,26 +150,31 @@ function tableInit(ctx){
137 var end = tableParams.page + 2; 150 var end = tableParams.page + 2;
138 var numPages = Math.ceil(tableData.total/tableParams.limit); 151 var numPages = Math.ceil(tableData.total/tableParams.limit);
139 152
140 if (tableParams.page < 3) 153 if (numPages > 1){
141 end = 5; 154 if (tableParams.page < 3)
155 end = 5;
142 156
143 for (var page_i=1; page_i <= numPages; page_i++){ 157 for (var page_i=1; page_i <= numPages; page_i++){
144 if (page_i >= start && page_i <= end){ 158 if (page_i >= start && page_i <= end){
145 var btn = $('<li><a href="#" class="page">'+page_i+'</a></li>'); 159 var btn = $('<li><a href="#" class="page">'+page_i+'</a></li>');
146 160
147 if (page_i === tableParams.page){ 161 if (page_i === tableParams.page){
148 btn.addClass("active"); 162 btn.addClass("active");
149 } 163 }
150 164
151 /* Add the click handler */ 165 /* Add the click handler */
152 btn.click(pageButtonClicked); 166 btn.click(pageButtonClicked);
153 paginationBtns.append(btn); 167 paginationBtns.append(btn);
168 }
154 } 169 }
155 } 170 }
156 table.css("padding-bottom", 0); 171
157 loadColumnsPreference(); 172 loadColumnsPreference();
158 173
159 $("table").css("visibility", "visible"); 174 table.css("padding-bottom", 0);
175 tableContainer.css("visibility", "visible");
176
177 table.trigger("table-done", [tableData.total, tableParams]);
160 } 178 }
161 179
162 function setupTableChrome(tableData){ 180 function setupTableChrome(tableData){
@@ -374,9 +392,9 @@ function tableInit(ctx){
374 data: params, 392 data: params,
375 headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 393 headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
376 success: function (filterData) { 394 success: function (filterData) {
377 var filterActionRadios = $('#filter-actions'); 395 var filterActionRadios = $('#filter-actions-'+ctx.tableName);
378 396
379 $('#filter-modal-title').text(filterData.title); 397 $('#filter-modal-title-'+ctx.tableName).text(filterData.title);
380 398
381 filterActionRadios.text(""); 399 filterActionRadios.text("");
382 400
@@ -404,7 +422,7 @@ function tableInit(ctx){
404 filterActionRadios.append(action); 422 filterActionRadios.append(action);
405 } 423 }
406 424
407 $('#filter-modal').modal('show'); 425 $('#filter-modal-'+ctx.tableName).modal('show');
408 } 426 }
409 }); 427 });
410 } 428 }
@@ -417,17 +435,18 @@ function tableInit(ctx){
417 e.stopPropagation(); 435 e.stopPropagation();
418 }); 436 });
419 437
420 $(".pagesize").val(tableParams.limit); 438 $(".pagesize-"+ctx.tableName).val(tableParams.limit);
421 439
422 /* page size selector */ 440 /* page size selector */
423 $(".pagesize").change(function(){ 441 $(".pagesize-"+ctx.tableName).change(function(e){
424 tableParams.limit = Number(this.value); 442 tableParams.limit = Number(this.value);
425 if ((tableParams.page * tableParams.limit) > tableTotal) 443 if ((tableParams.page * tableParams.limit) > tableTotal)
426 tableParams.page = 1; 444 tableParams.page = 1;
427 445
428 loadData(tableParams); 446 loadData(tableParams);
429 /* sync the other selectors on the page */ 447 /* sync the other selectors on the page */
430 $(".pagesize").val(this.value); 448 $(".pagesize-"+ctx.tableName).val(this.value);
449 e.preventDefault();
431 }); 450 });
432 451
433 $("#search-submit-"+ctx.tableName).click(function(e){ 452 $("#search-submit-"+ctx.tableName).click(function(e){
@@ -463,12 +482,12 @@ function tableInit(ctx){
463 e.preventDefault(); 482 e.preventDefault();
464 }); 483 });
465 484
466 $("#clear-filter-btn").click(function(){ 485 $("#clear-filter-btn-"+ctx.tableName).click(function(){
467 tableParams.filter = null; 486 tableParams.filter = null;
468 loadData(tableParams); 487 loadData(tableParams);
469 }); 488 });
470 489
471 $("#filter-modal-form").submit(function(e){ 490 $("#filter-modal-form-"+ctx.tableName).submit(function(e){
472 e.preventDefault(); 491 e.preventDefault();
473 492
474 tableParams.filter = $(this).find("input[type='radio']:checked").val(); 493 tableParams.filter = $(this).find("input[type='radio']:checked").val();
diff --git a/bitbake/lib/toaster/toastergui/tables.py b/bitbake/lib/toaster/toastergui/tables.py
index e6395834a5..78a7cb095e 100644
--- a/bitbake/lib/toaster/toastergui/tables.py
+++ b/bitbake/lib/toaster/toastergui/tables.py
@@ -132,7 +132,6 @@ class LayersTable(ToasterTable):
132 static_data_name="add-del-layers", 132 static_data_name="add-del-layers",
133 static_data_template='{% include "layer_btn.html" %}') 133 static_data_template='{% include "layer_btn.html" %}')
134 134
135
136class MachinesTable(ToasterTable): 135class MachinesTable(ToasterTable):
137 """Table of Machines in Toaster""" 136 """Table of Machines in Toaster"""
138 137
@@ -178,8 +177,7 @@ class MachinesTable(ToasterTable):
178 self.add_column(title="Machine file", 177 self.add_column(title="Machine file",
179 hidden=True, 178 hidden=True,
180 static_data_name="machinefile", 179 static_data_name="machinefile",
181 static_data_template=machine_file_template, 180 static_data_template=machine_file_template)
182 field_name="name")
183 181
184 self.add_column(title="Select", 182 self.add_column(title="Select",
185 help_text="Sets the selected machine as the project machine. You can only have one machine per project", 183 help_text="Sets the selected machine as the project machine. You can only have one machine per project",
@@ -189,6 +187,33 @@ class MachinesTable(ToasterTable):
189 field_name="layer_version__id") 187 field_name="layer_version__id")
190 188
191 189
190class LayerMachinesTable(MachinesTable):
191 """ Smaller version of the Machines table for use in layer details """
192
193 def __init__(self, *args, **kwargs):
194 MachinesTable.__init__(self)
195
196 def setup_queryset(self, *args, **kwargs):
197 MachinesTable.setup_queryset(self, *args, **kwargs)
198
199 self.queryset = self.queryset.filter(layer_version__pk=int(kwargs['layerid']))
200 self.static_context_extra['in_prj'] = ProjectLayer.objects.filter(Q(project=kwargs['pid']) and Q(layercommit=kwargs['layerid'])).count()
201
202 def setup_columns(self, *args, **kwargs):
203 self.add_column(title="Machine",
204 hideable=False,
205 orderable=True,
206 field_name="name")
207
208 self.add_column(title="Description",
209 field_name="description")
210
211 select_btn_template = '<a href="{% url "project" extra.pid %}#/machineselect={{data.name}}" class="btn btn-block select-machine-btn" {% if extra.in_prj == 0%}disabled="disabled"{%endif%}>Select machine</a>'
212
213 self.add_column(title="Select machine",
214 static_data_name="add-del-layers",
215 static_data_template=select_btn_template)
216
192 217
193class RecipesTable(ToasterTable): 218class RecipesTable(ToasterTable):
194 """Table of Recipes in Toaster""" 219 """Table of Recipes in Toaster"""
@@ -267,13 +292,57 @@ class RecipesTable(ToasterTable):
267 static_data_name="add-del-layers", 292 static_data_name="add-del-layers",
268 static_data_template='{% include "recipe_btn.html" %}') 293 static_data_template='{% include "recipe_btn.html" %}')
269 294
295class LayerRecipesTable(RecipesTable):
296 """ Smaller version of the Machines table for use in layer details """
297
298 def __init__(self, *args, **kwargs):
299 RecipesTable.__init__(self)
300
301 def setup_queryset(self, *args, **kwargs):
302 RecipesTable.setup_queryset(self, *args, **kwargs)
303 self.queryset = self.queryset.filter(layer_version__pk=int(kwargs['layerid']))
304
305 self.static_context_extra['in_prj'] = ProjectLayer.objects.filter(Q(project=kwargs['pid']) and Q(layercommit=kwargs['layerid'])).count()
306
307 def setup_columns(self, *args, **kwargs):
308 self.add_column(title="Recipe",
309 help_text="Information about a single piece of software, including where to download the source, configuration options, how to compile the source files and how to package the compiled output",
310 hideable=False,
311 orderable=True,
312 field_name="name")
313
314 self.add_column(title="Description",
315 field_name="get_description_or_summary")
316
317
318 build_recipe_template ='<button class="btn btn-block build-target-btn" data-target-name="{{data.name}}" {%if extra.in_prj == 0 %}disabled="disabled"{%endif%}>Build recipe</button>'
319
320 self.add_column(title="Build recipe",
321 static_data_name="add-del-layers",
322 static_data_template=build_recipe_template)
323
324
325
326
327
328
329
330
270# This needs to be staticaly defined here as django reads the url patterns 331# This needs to be staticaly defined here as django reads the url patterns
271# on start up 332# on start up
272urlpatterns = ( 333urlpatterns = (
273 url(r'^machines/(?P<cmd>\w+)*', MachinesTable.as_view(), 334 url(r'^machines/(?P<cmd>\w+)*', MachinesTable.as_view(),
274 name=MachinesTable.__name__.lower()), 335 name=MachinesTable.__name__.lower()),
275 url(r'^layers/(?P<cmd>\w+)*', LayersTable.as_view(), 336 url(r'^layers/(?P<cmd>\w+)*', LayersTable.as_view(),
276 name=LayersTable.__name__.lower()), 337 name=LayersTable.__name__.lower()),
277 url(r'^recipes/(?P<cmd>\w+)*', RecipesTable.as_view(), 338 url(r'^recipes/(?P<cmd>\w+)*', RecipesTable.as_view(),
278 name=RecipesTable.__name__.lower()), 339 name=RecipesTable.__name__.lower()),
340
341 # layer details tables
342 url(r'^layer/(?P<layerid>\d+)/recipes/(?P<cmd>\w+)*',
343 LayerRecipesTable.as_view(),
344 name=LayerRecipesTable.__name__.lower()),
345 url(r'^layer/(?P<layerid>\d+)/machines/(?P<cmd>\w+)*',
346 LayerMachinesTable.as_view(),
347 name=LayerMachinesTable.__name__.lower()),
279) 348)
diff --git a/bitbake/lib/toaster/toastergui/templates/layerdetails.html b/bitbake/lib/toaster/toastergui/templates/layerdetails.html
index 7b62b64893..259a59ea0a 100644
--- a/bitbake/lib/toaster/toastergui/templates/layerdetails.html
+++ b/bitbake/lib/toaster/toastergui/templates/layerdetails.html
@@ -36,13 +36,15 @@
36 projectBuildUrl : "{% url 'xhr_build' %}", 36 projectBuildUrl : "{% url 'xhr_build' %}",
37 layerDetailsUrl : "{% url 'base_layerdetails' project.id %}", 37 layerDetailsUrl : "{% url 'base_layerdetails' project.id %}",
38 xhrUpdateLayerUrl : "{% url 'xhr_updatelayer' %}", 38 xhrUpdateLayerUrl : "{% url 'xhr_updatelayer' %}",
39 numTargets : {{total_targets}},
40 numMachines: {{machines|length}},
41 layerVersion : { 39 layerVersion : {
42 name : "{{layerversion.layer.name}}", 40 name : "{{layerversion.layer.name}}",
43 id : {{layerversion.id}}, 41 id : {{layerversion.id}},
44 commit: "{{layerversion.get_vcs_reference}}", 42 commit: "{{layerversion.get_vcs_reference}}",
45 inCurrentPrj : {{layer_in_project}}, 43 {%if layerversion.id in projectlayers %}
44 inCurrentPrj : true,
45 {% else %}
46 inCurrentPrj : false,
47 {% endif %}
46 url : "{% url 'layerdetails' project.id layerversion.id %}", 48 url : "{% url 'layerdetails' project.id layerversion.id %}",
47 sourceId: {{layerversion.layer_source_id|json}}, 49 sourceId: {{layerversion.layer_source_id|json}},
48 } 50 }
@@ -57,437 +59,207 @@
57 }); 59 });
58</script> 60</script>
59 61
60 <div class="row-fluid span11"> 62<div class="row-fluid span11">
61 <div class="page-header"> 63 <div class="page-header">
62 <h1>{{layerversion.layer.name}} <small class="commit" 64 <h1>{{layerversion.layer.name}} <small class="commit"
63 {% if layerversion.get_vcs_reference|length > 13 %} 65 {% if layerversion.get_vcs_reference|length > 13 %}
64 data-toggle="tooltip" title="{{layerversion.get_vcs_reference}}" 66 data-toggle="tooltip" title="{{layerversion.get_vcs_reference}}"
65 {% endif %}> 67 {% endif %}>
66 ({{layerversion.get_vcs_reference|truncatechars:13}})</small></h1> 68 ({{layerversion.get_vcs_reference|truncatechars:13}})</small></h1>
67 </div>
68 </div> 69 </div>
70</div>
69 71
70 <div class="row-fluid span7 tabbable"> 72<!-- container for tabs -->
71 <div class="alert alert-info lead" id="alert-area" style="display:none"> 73<div class="row-fluid span7 tabbable">
72 <button type="button" class="close" id="dismiss-alert">&times;</button> 74 <div class="alert alert-info lead" id="alert-area" style="display:none">
73 <span id="alert-msg"></span> 75 <button type="button" class="close" id="dismiss-alert">&times;</button>
74 </div> 76 <span id="alert-msg"></span>
75 <ul class="nav nav-pills"> 77 </div>
76 <li class="active"> 78 <ul class="nav nav-pills">
77 <a data-toggle="tab" href="#information" id="details-tab">Layer details</a> 79 <li class="active">
78 </li> 80 <a data-toggle="tab" href="#information" id="details-tab">Layer details</a>
79 <li> 81 </li>
80 <a data-toggle="tab" href="#targets" id="targets-tab">Recipes ({{total_targets}})</a> 82 <li>
81 </li> 83 <a data-toggle="tab" href="#recipes" class="muted" id="targets-tab">Recipes (<span class="table-count-recipestable"></span>)</a>
82 <li> 84 </li>
83 <a data-toggle="tab" href="#machines" id="machines-tab">Machines ({{total_machines}})</a> 85 <li>
84 </li> 86 <a data-toggle="tab" href="#machines" class="muted" id="machines-tab">Machines (<span class="table-count-machinestable"></span>)</a>
85 </ul> 87 </li>
86 <div class="tab-content"> 88 </ul>
87 <span class="button-place"> 89 <div class="tab-content">
88 {% if layer_in_project == 0 %} 90 <span class="button-place">
89 <button id="add-remove-layer-btn" data-directive="add" class="btn btn-large btn-block"> 91 {% if layerversion.id not in projectlayers %}
90 <span class="icon-plus"></span> 92 <button id="add-remove-layer-btn" data-directive="add" class="btn btn-large btn-block">
91 Add the {{layerversion.layer.name}} layer to your project 93 <span class="icon-plus"></span>
92 </button> 94 Add the {{layerversion.layer.name}} layer to your project
93 {% else %} 95 </button>
94 <button id="add-remove-layer-btn" data-directive="remove" class="btn btn-block btn-large btn-danger"> 96 {% else %}
95 <span class="icon-trash"></span> 97 <button id="add-remove-layer-btn" data-directive="remove" class="btn btn-block btn-large btn-danger">
96 Delete the {{layerversion.layer.name}} layer from your project 98 <span class="icon-trash"></span>
97 </button> 99 Delete the {{layerversion.layer.name}} layer from your project
98 {% endif %} 100 </button>
99 </span> 101 {% endif %}
102 </span>
100 103
101 <!-- layer details pane --> 104 <!-- layer details pane -->
102 <div id="information" class="tab-pane active"> 105 <div id="information" class="tab-pane active">
103 <dl class="dl-horizontal"> 106 <dl class="dl-horizontal">
104 <dt class=""> 107 <dt class="">
105 <i class="icon-question-sign get-help" title="Fetch/clone URL of the repository"></i> 108 <i class="icon-question-sign get-help" title="Fetch/clone URL of the repository"></i>
106 Repository URL 109 Repository URL
110 </dt>
111 <dd>
112 <span class="current-value">{{layerversion.layer.vcs_url}}</span>
113 {% if layerversion.get_vcs_link_url %}
114 <a href="{{layerversion.get_vcs_link_url}}/" class="icon-share get-info" target="_blank"></a>
115 {% endif %}
116 <form id="change-repo-form" class="control-group" style="display:none">
117 <div class="input-append">
118 <input type="text" class="input-xlarge" value="{{layerversion.layer.vcs_url}}">
119 <button data-layer-prop="vcs_url" class="btn change-btn" type="button">Save</button>
120 <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a>
121 </div>
122 </form>
123 <i class="icon-pencil" ></i>
124 </dd>
125 <dt>
126 <i class="icon-question-sign get-help" title="Subdirectory within the repository where the layer is located, if not in the root (usually only used if the repository contains more than one layer)"></i>
127 Repository subdirectory
128 </dt>
129 <dd>
130 <span class="muted" style="display:none">Not set</span>
131 <span class="current-value">{{layerversion.dirpath}}</span>
132 {% if layerversion.get_vcs_dirpath_link_url %}
133 <a href="{{layerversion.get_vcs_dirpath_link_url}}" class="icon-share get-info" target="_blank"></a>
134 {% endif %}
135 <form id="change-subdir-form" style="display:none;">
136 <div class="input-append">
137 <input type="text" value="{{layerversion.dirpath}}">
138 <button data-layer-prop="dirpath" class="btn change-btn" type="button">Save</button>
139 <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a>
140 </div>
141 </form>
142 <i id="change-subdir" class="icon-pencil"></i>
143 <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span>
144 </dd>
145 <dt>
146 <i class="icon-question-sign get-help" title="The Git branch, tag or commit"></i>
147 Revision
107 </dt> 148 </dt>
108 <dd> 149 <dd>
109 <span class="current-value">{{layerversion.layer.vcs_url}}</span> 150 <span class="current-value">{{layerversion.get_vcs_reference}}</span>
110 {% if layerversion.get_vcs_link_url %} 151 <form style="display:none;">
111 <a href="{{layerversion.get_vcs_link_url}}/" class="icon-share get-info" target="_blank"></a>
112 {% endif %}
113 <form id="change-repo-form" class="control-group" style="display:none">
114 <div class="input-append"> 152 <div class="input-append">
115 <input type="text" class="input-xlarge" value="{{layerversion.layer.vcs_url}}"> 153 <input type="text" value="{{layerversion.get_vcs_reference}}">
116 <button data-layer-prop="vcs_url" class="btn change-btn" type="button">Save</button> 154 <button data-layer-prop="commit" class="btn change-btn" type="button">Save</button>
117 <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a> 155 <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a>
118 </div> 156 </div>
119 </form> 157 </form>
120 <i class="icon-pencil" ></i> 158 <i class="icon-pencil"></i>
121 </dd> 159 </dd>
122 <dt> 160 <dt>
123 <i class="icon-question-sign get-help" title="Subdirectory within the repository where the layer is located, if not in the root (usually only used if the repository contains more than one layer)"></i> 161 <i class="icon-question-sign get-help" title="Other layers this layer depends upon"></i>
124 Repository subdirectory 162 Layer dependencies
125 </dt> 163 </dt>
126 <dd> 164 <dd>
127 <span class="muted" style="display:none">Not set</span> 165 <ul class="unstyled current-value" id="layer-deps-list">
128 <span class="current-value">{{layerversion.dirpath}}</span> 166 {% for ld in layerversion.dependencies.all %}
129 {% if layerversion.get_vcs_dirpath_link_url %} 167 <li data-layer-id="{{ld.depends_on.id}}">
130 <a href="{{layerversion.get_vcs_dirpath_link_url}}" class="icon-share get-info" target="_blank"></a> 168 <a data-toggle="tooltip" title="{{ld.depends_on.layer.vcs_url}} | {{ld.depends_on.get_vcs_reference}}" href="{% url 'layerdetails' project.id ld.depends_on.id %}">{{ld.depends_on.layer.name}}</a>
131 {% endif %} 169 <span class="icon-trash " data-toggle="tooltip" title="Delete"></span>
132 <form id="change-subdir-form" style="display:none;"> 170 </li>
133 <div class="input-append"> 171 {% endfor %}
134 <input type="text" value="{{layerversion.dirpath}}"> 172 </ul>
135 <button data-layer-prop="dirpath" class="btn change-btn" type="button">Save</button> 173 <div class="input-append add-deps">
136 <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a> 174 <input type="text" autocomplete="off" data-minLength="1" data-autocomplete="off" placeholder="Type a layer name" id="layer-dep-input">
137 </div> 175 <a class="btn" id="add-layer-dependency-btn" >
138 </form> 176 Add layer
139 <i id="change-subdir" class="icon-pencil"></i> 177 </a>
140 <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span>
141 </dd>
142 <dt>
143 <i class="icon-question-sign get-help" title="The Git branch, tag or commit"></i>
144 Revision
145 </dt>
146 <dd>
147 <span class="current-value">{{layerversion.get_vcs_reference}}</span>
148 <form style="display:none;">
149 <div class="input-append">
150 <input type="text" value="{{layerversion.get_vcs_reference}}">
151 <button data-layer-prop="commit" class="btn change-btn" type="button">Save</button>
152 <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a>
153 </div>
154 </form>
155 <i class="icon-pencil"></i>
156 </dd>
157 <dt>
158 <i class="icon-question-sign get-help" title="Other layers this layer depends upon"></i>
159 Layer dependencies
160 </dt>
161 <dd>
162 <ul class="unstyled current-value" id="layer-deps-list">
163 {% for ld in layerversion.dependencies.all %}
164 <li data-layer-id="{{ld.depends_on.id}}">
165 <a data-toggle="tooltip" title="{{ld.depends_on.layer.vcs_url}} | {{ld.depends_on.get_vcs_reference}}" href="{% url 'layerdetails' project.id ld.depends_on.id %}">{{ld.depends_on.layer.name}}</a>
166 <span class="icon-trash " data-toggle="tooltip" title="Delete"></span>
167 </li>
168 {% endfor %}
169 </ul>
170 <div class="input-append add-deps">
171 <input type="text" autocomplete="off" data-minLength="1" data-autocomplete="off" placeholder="Type a layer name" id="layer-dep-input">
172 <a class="btn" id="add-layer-dependency-btn" >
173 Add layer
174 </a>
175 </div>
176 <span class="help-block add-deps">You can only add layers Toaster knows about</span>
177 </dd>
178 </dl>
179 </div>
180 <!-- targets tab -->
181 <div id="targets" class="tab-pane">
182 {% if total_targets == 0 %}
183 <div class="alert alert-info">
184 <p>Toaster does not have recipe information for the <strong> {{layerversion.layer.name}} </strong> layer.</p>
185 <p>Toaster learns about layers when you build them. If this layer provides any recipes, they will be listed here after you build the <strong> {{layerversion.layer.name}} </strong> layer.</p>
186 </div>
187 {% else %}
188
189 <div class="row-fluid">
190
191 {% if targets.paginator.count == 0 %}
192 <div class="alert">
193 <h3>No targets found</h3>
194 {% endif %}
195
196 {# only show the search form if we have more than 10 results #}
197 {% if targets.paginator.count > 10 or request.GET.targets_search %}
198 {% if targets.paginator.count == 0 %}
199 <form class="input-append">
200 {% else %}
201 <form class="navbar-search input-append pull-left">
202 {% endif %}
203
204 <input type="text" id="target-search" name="targets_search" placeholder="Search recipes" class="input-xlarge" value="{{request.GET.targets_search}}">
205 {% if request.GET.targets_search %}
206 <a class="add-on btn target-search-clear">
207 <i class="icon-remove"></i>
208 </a>
209 {% endif %}
210 <button type="submit" class="btn">Search</button>
211 {% if targets.paginator.count == 0 %}
212 <button type="submit" class="btn btn-link target-search-clear">Show all targets</a>
213 {% endif %}
214 </form>
215 {% endif %}
216
217 {% if targets.paginator.count == 0 %}
218 <!-- end alert -->
219 </div>
220 <!-- end row-fluid -->
221 </div>
222 {% else %}
223
224 {% if total_targets > 10 %}
225 <div class="pull-right">
226 <span class="help-inline" style="padding-top:5px;">Show rows:</span>
227 <select style="margin-top:5px;margin-bottom:0px;" class="pagesize">
228 {% with "10 25 50 100 150" as list%}
229 {% for i in list.split %}
230 {% if request.session.limit == i %}
231 <option value="{{i}}" selected>{{i}}</option>
232 {% else %}
233 <option value="{{i}}">{{i}}</option>
234 {% endif %}
235 {% endfor %}
236 {% endwith %}
237 </select>
238 </div>
239 {% endif %}
240 </div>
241
242 <table class="table table-bordered table-hover">
243 <thead>
244 <tr>
245 <th>
246 <i class="icon-question-sign get-help" title="Information about a single piece of software, including where to download the source, configuration options, how to compile the source files and how to package the compiled output"></i>
247 Recipe
248 {% if request.GET.targets_search %}
249 <span class="badge badge-info">{{targets.paginator.count}}</span>
250 {% endif %}
251 </th>
252 <th>
253 <i class="icon-question-sign get-help" title="The recipe version and revision"></i>
254 Recipe version
255 </th>
256 <th class="span4">Summary</th>
257 <th class="span2">Build recipe</th>
258 </tr>
259 </thead>
260 <tbody>
261 {% for target in targets %}
262 <tr>
263 <td>
264 {{target.name}}
265 {% if target.up_id %}
266 <a href="{{target.get_layersource_view_url}}" class="icon-share get-info" target="_blank"></a>
267 {% endif %}
268 </td>
269 <td>{{target.version}}</td>
270 <td>{{target.summary}}</td>
271 <td><button class="btn btn-block build-target-btn" data-target-name="{{target.name}}" {% if layer_in_project == 0 %}disabled="disabled"{% endif %} >Build recipe</button></td>
272 </tr>
273 {% endfor %}
274 </tbody>
275 </table>
276
277 {% if total_targets > 10 %}
278 <!-- Show pagination controls -->
279 <div class="pagination">
280 <ul>
281 {%if targets.has_previous %}
282 <li><a href="?tpage={{targets.previous_page_number}}{{request.GET.limit}}#targets">&laquo;</a></li>
283 {%else%}
284 <li class="disabled"><a href="#">&laquo;</a></li>
285 {%endif%}
286 {% for i in targets.page_range %}
287 <li {%if i == targets.number %} class="active" {%endif%}><a href="?tpage={{i}}#targets">{{i}}</a></li>
288 {% endfor %}
289 {%if targets.has_next%}
290 <li><a href="?tpage={{targets.next_page_number}}#targets">&raquo;</a></li>
291 {%else%}
292 <li class="disabled"><a href="#">&raquo;</a></li>
293 {%endif%}
294 </ul>
295 <div class="pull-right">
296 <span class="help-inline" style="padding-bottom:10px;">Show rows:</span>
297 <select class="pagesize">
298 {% with "10 25 50 100 150" as list%}
299 {% for i in list.split %}
300 {% if request.session.limit == i %}
301 <option value="{{i}}" selected>{{i}}</option>
302 {% else %}
303 <option value="{{i}}">{{i}}</option>
304 {% endif %}
305 {% endfor %}
306 {% endwith %}
307 </select>
308 </div>
309 </div>
310 {% endif %}
311 {% endif %}
312 {% endif %}
313 </div>
314
315
316 <div id="machines" class="tab-pane">
317 {% if total_machines == 0 %}
318 <div class="alert alert-info">
319 <p>Toaster does not have machine information for the <strong> {{layerversion.layer.name}} </strong> layer.</p>
320 <p>Toaster learns about layers when you build them. If this layer provides any machines, they will be listed here after you build the <strong> {{layerversion.layer.name}} </strong> layer.</p>
321 </div> 178 </div>
322 {% else %} 179 <span class="help-block add-deps">You can only add layers Toaster knows about</span>
323 180 </dd>
324 <div class="row-fluid"> 181 </dl>
325 182 </div>
326 {% if machines.paginator.count == 0 %} 183 <!-- end layerdetails tab -->
327 <div class="alert"> 184 <!-- targets tab -->
328 <h3>No machines found</h3> 185 <div id="recipes" class="tab-pane">
329 {% endif %} 186 <!-- Recipe table -->
330 187 <div id="no-recipes-yet" class="alert alert-info" style="display:none">
331 {# only show the search form if we have more than 10 results #} 188 <p>Toaster does not have recipe information for the <strong> {{layerversion.layer.name}} </strong> layer.</p>
332 {% if machines.paginator.count > 10 or request.GET.machines_search %} 189 <p>Toaster learns about layers when you build them. If this layer provides any recipes, they will be listed here after you build the <strong> {{layerversion.layer.name}} </strong> layer.</p>
333 {% if machines.paginator.count == 0 %} 190 </div>
334 <form class="input-append">
335 {% else %}
336 <form class="navbar-search input-append pull-left">
337 {% endif %}
338 191
339 <input type="text" id="machine-search" name="machines_search" placeholder="Search machines" class="input-xlarge" value="{{request.GET.machines_search}}">
340 {% if request.GET.machines_search %}
341 <a class="add-on btn machine-search-clear">
342 <i class="icon-remove"></i>
343 </a>
344 {% endif %}
345 <button type="submit" class="btn">Search</button>
346 {% if machines.paginator.count == 0 %}
347 <button type="submit" class="btn btn-link machine-search-clear">Show all machines</a>
348 {% endif %}
349 </form>
350 {% endif %}
351 192
352 {% if machines.paginator.count == 0 %}
353 <!-- end alert -->
354 </div>
355 <!-- end row-fluid -->
356 </div>
357 193
358 {% else %} 194 {% url 'layerrecipestable' project.id layerversion.id as xhr_table_url %}
195 {% with "recipestable" as table_name %}
196 {% with "Recipes" as title %}
197 {% include 'toastertable-simple.html' %}
198 {% endwith %}
199 {% endwith %}
200 </div>
359 201
360 {% if total_machines > 10 %} 202 <div id="machines" class="tab-pane">
361 <div class="pull-right">
362 <span class="help-inline" style="padding-top:5px;">Show rows:</span>
363 <select style="margin-top:5px;margin-bottom:0px;" class="pagesize">
364 {% with "10 25 50 100 150" as list%}
365 {% for i in list.split %}
366 {% if request.session.limit == i %}
367 <option value="{{i}}" selected>{{i}}</option>
368 {% else %}
369 <option value="{{i}}">{{i}}</option>
370 {% endif %}
371 {% endfor %}
372 {% endwith %}
373 </select>
374 </div>
375 {% endif %}
376 203
377 </div> 204 <div id="no-machines-yet" class="alert alert-info" style="display:none">
205 <p>Toaster does not have machine information for the <strong> {{layerversion.layer.name}} </strong> layer.</p>
206 <p>Toaster learns about layers when you build them. If this layer provides any machines, they will be listed here after you build the <strong> {{layerversion.layer.name}} </strong> layer.</p>
207 </div>
378 208
379 <table class="table table-bordered table-hover">
380 <thead>
381 <tr>
382 <th>
383 <i class="icon-question-sign get-help" title="The machine is the hardware for which you are building"></i>
384 Machine
385 {% if request.GET.machines_search %}
386 <span class="badge badge-info">{{machines.paginator.count}}</span>
387 {% endif %}
388 </th>
389 <th>Description</th>
390 <th class="span2">Select machine</th>
391 </tr>
392 </thead>
393 <tbody>
394 {% for machine in machines %}
395 <tr>
396 <td>
397 {{machine.name}}
398 {% if machine.get_vcs_machine_file_link_url %}
399 <a href="{{machine.get_vcs_machine_file_link_url}}" target="_blank"><i class="icon-share get-info"></i></a>
400 {% endif %}
401 </td>
402 <td>{{machine.description}}</td>
403 <td>
404 <a href="{% url 'project' project.id %}#/machineselect={{machine.name}}" class="btn btn-block select-machine-btn" {% if layer_in_project == 0 %}disabled="disabled"{% endif %}>Select machine</a>
405 </tr>
406 {% endfor %}
407 </tbody>
408 </table>
409 209
410 {% if total_machines > 10 %} 210 <!-- Machines table -->
411 <!-- Show pagination controls --> 211 {% url 'layermachinestable' project.id layerversion.id as xhr_table_url %}
412 <div class="pagination"> 212 {% with "machinestable" as table_name %}
413 <ul> 213 {% with "Machines" as title %}
414 {%if machines.has_previous %} 214 {% include 'toastertable-simple.html' %}
415 <li><a href="?mpage={{machines.previous_page_number}}{{request.GET.limit}}#machines">&laquo;</a></li> 215 {% endwith %}
416 {%else%} 216 {% endwith %}
417 <li class="disabled"><a href="#">&laquo;</a></li>
418 {%endif%}
419 {% for i in machines.page_range %}
420 <li {%if i == machines.number %} class="active" {%endif%}><a href="?mpage={{i}}#machines">{{i}}</a></li>
421 {% endfor %}
422 {%if machines.has_next%}
423 <li><a href="?mpage={{machines.next_page_number}}#machines">&raquo;</a></li>
424 {%else%}
425 <li class="disabled"><a href="#">&raquo;</a></li>
426 {%endif%}
427 </ul>
428 <div class="pull-right">
429 <span class="help-inline" style="padding-bottom:10px;">Show rows:</span>
430 <select class="pagesize">
431 {% with "10 25 50 100 150" as list%}
432 {% for i in list.split %}
433 {% if request.session.limit == i %}
434 <option value="{{i}}" selected>{{i}}</option>
435 {% else %}
436 <option value="{{i}}">{{i}}</option>
437 {% endif %}
438 {% endfor %}
439 {% endwith %}
440 </select>
441 </div>
442 </div>
443 {% endif %}
444 {% endif %}
445 {% endif %}
446 </div>
447 </div>
448 </div> 217 </div>
449 <div class="row-fluid span4 well"> 218 </div> <!-- end tab content -->
450 <h2>About {{layerversion.layer.name}}</h2> 219 </div> <!-- end tabable -->
451 <dl class="item-info">
452 220
453 <dt> 221 <div class="row-fluid span4 well"> <!-- info side panel -->
454 Summary 222 <h2>About {{layerversion.layer.name}}</h2>
455 <i class="icon-question-sign get-help" title="One-line description of the layer"></i> 223 <dl class="item-info">
456 </dt>
457 <dd>
458 <span class="muted" style="display:none">Not set</span>
459 <span class="current-value">{{layerversion.layer.summary|default_if_none:''}}</span>
460 <form style="display:none; margin-bottom:20px">
461 <textarea class="span12" rows="2">{% if layerversion.layer.summary %}{{layerversion.layer.summary}}{% endif %}</textarea>
462 <button class="btn change-btn" data-layer-prop="summary" type="button">Save</button>
463 <a href="#" class="btn btn-link cancel">Cancel</a>
464 </form>
465 <i class="icon-pencil"></i>
466 <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span>
467 </dd>
468 <dt>
469 Description
470 </dt>
471 <dd>
472 <span class="muted" style="display:none">Not set</span>
473 <span class="current-value">{{layerversion.layer.description|default_if_none:''}}</span>
474 <form style="display:none; margin-bottom:20px">
475 <textarea class="span12" rows="6">{% if layerversion.layer.description %}{{layerversion.layer.description}}{% endif %}</textarea>
476 <button class="btn change-btn" data-layer-prop="description" type="button" >Save</button>
477 <a href="#" class="btn btn-link cancel">Cancel</a>
478 </form>
479 <i class="icon-pencil"></i>
480 <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span>
481 </dd>
482 {% if layerversion.layer.up_id %}
483 <dt>Layer index</dt>
484 <dd>
485 <a href="http://layers.openembedded.org/layerindex/branch/{{layerversion.up_branch.name}}/layer/{{layerversion.layer.name}}"/>layer index link</a>
486 224
487 </dd> 225 <dt>
488 {% endif %} 226 Summary
227 <i class="icon-question-sign get-help" title="One-line description of the layer"></i>
228 </dt>
229 <dd>
230 <span class="muted" style="display:none">Not set</span>
231 <span class="current-value">{{layerversion.layer.summary|default_if_none:''}}</span>
232 <form style="display:none; margin-bottom:20px">
233 <textarea class="span12" rows="2">{% if layerversion.layer.summary %}{{layerversion.layer.summary}}{% endif %}</textarea>
234 <button class="btn change-btn" data-layer-prop="summary" type="button">Save</button>
235 <a href="#" class="btn btn-link cancel">Cancel</a>
236 </form>
237 <i class="icon-pencil"></i>
238 <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span>
239 </dd>
240 <dt>
241 Description
242 </dt>
243 <dd>
244 <span class="muted" style="display:none">Not set</span>
245 <span class="current-value">{{layerversion.layer.description|default_if_none:''}}</span>
246 <form style="display:none; margin-bottom:20px">
247 <textarea class="span12" rows="6">{% if layerversion.layer.description %}{{layerversion.layer.description}}{% endif %}</textarea>
248 <button class="btn change-btn" data-layer-prop="description" type="button" >Save</button>
249 <a href="#" class="btn btn-link cancel">Cancel</a>
250 </form>
251 <i class="icon-pencil"></i>
252 <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span>
253 </dd>
254 {% if layerversion.layer.up_id %}
255 <dt>Layer index</dt>
256 <dd>
257 <a href="http://layers.openembedded.org/layerindex/branch/{{layerversion.up_branch.name}}/layer/{{layerversion.layer.name}}">layer index link</a>
258
259 </dd>
260 {% endif %}
489 261
490 </dl> 262 </dl>
491 </div> 263 </div>
492 264
493{% endblock %} 265 {% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/templates/toastertable-filter.html b/bitbake/lib/toaster/toastergui/templates/toastertable-filter.html
new file mode 100644
index 0000000000..7c8dc49b33
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/toastertable-filter.html
@@ -0,0 +1,18 @@
1<!-- filter modal -->
2<div id="filter-modal-{{table_name}}" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="false">
3 <form id="filter-modal-form-{{table_name}}" style="margin-bottom: 0px">
4 <div class="modal-header">
5 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
6 <h3 id="filter-modal-title-{{table_name}}">&nbsp;</h3>
7 </div>
8 <div class="modal-body">
9 <p>Show:</p>
10 <span id="filter-actions-{{table_name}}"></span>
11 </div>
12 <div class="modal-footer">
13 <button class="btn btn-primary" type="submit">Apply</button>
14 </div>
15 </form>
16</div>
17<button id="clear-filter-btn-{{table_name}}" style="display:none"></button>
18<!-- end filter modal -->
diff --git a/bitbake/lib/toaster/toastergui/templates/toastertable-simple.html b/bitbake/lib/toaster/toastergui/templates/toastertable-simple.html
index 98cad64a01..23a75260a1 100644
--- a/bitbake/lib/toaster/toastergui/templates/toastertable-simple.html
+++ b/bitbake/lib/toaster/toastergui/templates/toastertable-simple.html
@@ -24,23 +24,7 @@
24 }); 24 });
25</script> 25</script>
26 26
27<!-- filter modal --> 27{% include 'toastertable-filter.html' %}
28<div id="filter-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="false">
29 <form id="filter-modal-form" style="margin-bottom: 0px">
30 <div class="modal-header">
31 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
32 <h3 id="filter-modal-title">&nbsp;</h3>
33 </div>
34 <div class="modal-body">
35 <p>Show:</p>
36 <span id="filter-actions"></span>
37 </div>
38 <div class="modal-footer">
39 <button class="btn btn-primary" type="submit">Apply</button>
40 </div>
41 </form>
42</div>
43<button id="clear-filter-btn" style="display:none"></button>
44 28
45<div class="row-fluid" id="no-results-{{table_name}}" style="display:none"> 29<div class="row-fluid" id="no-results-{{table_name}}" style="display:none">
46 <div class="alert"> 30 <div class="alert">
@@ -55,9 +39,7 @@
55 </form> 39 </form>
56 </div> 40 </div>
57</div> 41</div>
58 42<div id="table-container-{{table_name}}" style="visibility: hidden">
59
60<div id="table-container-{{table_name}}">
61 <!-- control header --> 43 <!-- control header -->
62 <div class="row-fluid" id="table-chrome-{{table_name}}"> 44 <div class="row-fluid" id="table-chrome-{{table_name}}">
63 <div class="navbar-search input-append pull-left"> 45 <div class="navbar-search input-append pull-left">
@@ -94,8 +76,8 @@
94 </table> 76 </table>
95 77
96 <!-- Pagination controls --> 78 <!-- Pagination controls -->
97 <div class="pagination pagination-centered"> 79 <div class="pagination pagination-centered" id="pagination-{{table_name}}">
98 <ul id="pagination-{{table_name}}" class="pagination" style="display: block-inline"> 80 <ul class="pagination" style="display: block-inline">
99 </ul> 81 </ul>
100 82
101 <div class="pull-right"> 83 <div class="pull-right">
diff --git a/bitbake/lib/toaster/toastergui/templates/toastertable.html b/bitbake/lib/toaster/toastergui/templates/toastertable.html
index 4e6c4ce4d2..5c79ab4ae1 100644
--- a/bitbake/lib/toaster/toastergui/templates/toastertable.html
+++ b/bitbake/lib/toaster/toastergui/templates/toastertable.html
@@ -24,37 +24,23 @@
24 }); 24 });
25</script> 25</script>
26 26
27<!-- filter modal --> 27{% include 'toastertable-filter.html' %}
28<div id="filter-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="false">
29 <form id="filter-modal-form" style="margin-bottom: 0px">
30 <div class="modal-header">
31 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
32 <h3 id="filter-modal-title">&nbsp;</h3>
33 </div>
34 <div class="modal-body">
35 <p>Show:</p>
36 <span id="filter-actions"></span>
37 </div>
38 <div class="modal-footer">
39 <button class="btn btn-primary" type="submit">Apply</button>
40 </div>
41 </form>
42</div>
43<button id="clear-filter-btn" style="display:none"></button>
44 28
45<div class="row-fluid alert" id="no-results-{{table_name}}" style="display:none"> 29<div class="row-fluid" id="no-results-{{table_name}}" style="display:none">
46 <form class="no-results input-append"> 30 <div class="alert">
47 <input class="input-xxlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/> 31 <form class="no-results input-append">
48 <a href="#" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1"> 32 <input class="input-xxlarge" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{{request.GET.search}}"/>
49 <i class="icon-remove"></i> 33 <a href="#" class="add-on btn remove-search-btn-{{table_name}}" tabindex="-1">
50 </a> 34 <i class="icon-remove"></i>
51 <button class="btn search-submit-{{table_name}}" >Search</button> 35 </a>
52 <button class="btn btn-link remove-search-btn-{{table_name}}">Show {{title|lower}} 36 <button class="btn search-submit-{{table_name}}" >Search</button>
53 </button> 37 <button class="btn btn-link remove-search-btn-{{table_name}}">Show {{title|lower}}
54 </form> 38 </button>
39 </form>
40 </div>
55</div> 41</div>
56 42
57<div id="table-container-{{table_name}}"> 43<div id="table-container-{{table_name}}" style="visibility: hidden">
58 <!-- control header --> 44 <!-- control header -->
59 <div class="navbar" id="table-chrome-{{table_name}}"> 45 <div class="navbar" id="table-chrome-{{table_name}}">
60 <div class="navbar-inner"> 46 <div class="navbar-inner">
@@ -78,7 +64,7 @@
78 <div style="display:inline"> 64 <div style="display:inline">
79 <span class="divider-vertical"></span> 65 <span class="divider-vertical"></span>
80 <span class="help-inline" style="padding-top:5px;">Show rows:</span> 66 <span class="help-inline" style="padding-top:5px;">Show rows:</span>
81 <select style="margin-top:5px;margin-bottom:0px;" class="pagesize"> 67 <select style="margin-top:5px;margin-bottom:0px;" class="pagesize-{{table_name}}">
82 {% with "10 25 50 100 150" as list%} 68 {% with "10 25 50 100 150" as list%}
83 {% for i in list.split %} 69 {% for i in list.split %}
84 <option value="{{i}}">{{i}}</option> 70 <option value="{{i}}">{{i}}</option>
@@ -99,13 +85,13 @@
99 </table> 85 </table>
100 86
101 <!-- Pagination controls --> 87 <!-- Pagination controls -->
102 <div class="pagination pagination-centered"> 88 <div class="pagination pagination-centered" id="pagination-{{table_name}}">
103 <ul id="pagination-{{table_name}}" class="pagination" style="display: block-inline"> 89 <ul class="pagination" style="display: block-inline">
104 </ul> 90 </ul>
105 91
106 <div class="pull-right"> 92 <div class="pull-right">
107 <span class="help-inline" style="padding-top:5px;">Show rows:</span> 93 <span class="help-inline" style="padding-top:5px;">Show rows:</span>
108 <select style="margin-top:5px;margin-bottom:0px;" class="pagesize"> 94 <select style="margin-top:5px;margin-bottom:0px;" class="pagesize-{{table_name}}">
109 {% with "10 25 50 100 150" as list%} 95 {% with "10 25 50 100 150" as list%}
110 {% for i in list.split %} 96 {% for i in list.split %}
111 <option value="{{i}}">{{i}}</option> 97 <option value="{{i}}">{{i}}</option>
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py
index d0c176b593..7a1132febc 100644
--- a/bitbake/lib/toaster/toastergui/urls.py
+++ b/bitbake/lib/toaster/toastergui/urls.py
@@ -83,7 +83,9 @@ urlpatterns = patterns('toastergui.views',
83 url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'), 83 url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'),
84 url(r'^project/(?P<pid>\d+)/builds/$', 'projectbuilds', name='projectbuilds'), 84 url(r'^project/(?P<pid>\d+)/builds/$', 'projectbuilds', name='projectbuilds'),
85 85
86 url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$', 'layerdetails', name='layerdetails'), 86 url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$',
87 ToasterTemplateView.as_view(template_name='layerdetails.html'),
88 name='layerdetails'),
87 url(r'^project/(?P<pid>\d+)/layer/$', lambda x,pid: HttpResponseBadRequest(), name='base_layerdetails'), 89 url(r'^project/(?P<pid>\d+)/layer/$', lambda x,pid: HttpResponseBadRequest(), name='base_layerdetails'),
88 90
89 # the import layer is a project-specific functionality; 91 # the import layer is a project-specific functionality;
@@ -117,7 +119,7 @@ urlpatterns = patterns('toastergui.views',
117 url(r'^xhr_datatypeahead/(?P<pid>\d+)$', 'xhr_datatypeahead', name='xhr_datatypeahead'), 119 url(r'^xhr_datatypeahead/(?P<pid>\d+)$', 'xhr_datatypeahead', name='xhr_datatypeahead'),
118 url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'), 120 url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'),
119 url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'), 121 url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'),
120 url(r'^xhr_tables/(?P<pid>\d+)/', include('toastergui.tables')), 122 url(r'^xhr_tables/project/(?P<pid>\d+)/', include('toastergui.tables')),
121 123
122 # dashboard for failed build requests 124 # dashboard for failed build requests
123 url(r'^project/(?P<pid>\d+)/buildrequest/(?P<brid>\d+)$', 'buildrequestdetails', name='buildrequestdetails'), 125 url(r'^project/(?P<pid>\d+)/buildrequest/(?P<brid>\d+)$', 'buildrequestdetails', name='buildrequestdetails'),
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index d451c3b927..f70cf205b7 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -2664,52 +2664,6 @@ if toastermain.settings.MANAGED:
2664 } 2664 }
2665 return render(request, template, context) 2665 return render(request, template, context)
2666 2666
2667
2668
2669 def layerdetails(request, pid, layerid):
2670 template = "layerdetails.html"
2671 limit = 10
2672
2673 if request.GET.has_key("limit"):
2674 request.session['limit'] = request.GET['limit']
2675
2676 if request.session.has_key('limit'):
2677 limit = request.session['limit']
2678
2679 layer_version = Layer_Version.objects.get(pk = layerid)
2680
2681 targets_query = Recipe.objects.filter(layer_version=layer_version)
2682
2683 # Targets tab query functionality
2684 if request.GET.has_key('targets_search'):
2685 targets_query = targets_query.filter(
2686 Q(name__icontains=request.GET['targets_search']) |
2687 Q(summary__icontains=request.GET['targets_search']))
2688
2689 targets = _build_page_range(Paginator(targets_query.order_by("name"), limit), request.GET.get('tpage', 1))
2690
2691 machines_query = Machine.objects.filter(layer_version=layer_version)
2692
2693 # Machines tab query functionality
2694 if request.GET.has_key('machines_search'):
2695 machines_query = machines_query.filter(
2696 Q(name__icontains=request.GET['machines_search']) |
2697 Q(description__icontains=request.GET['machines_search']))
2698
2699 machines = _build_page_range(Paginator(machines_query.order_by("name"), limit), request.GET.get('mpage', 1))
2700
2701 context = {
2702 'project' : Project.objects.get(pk=pid),
2703 'layerversion': layer_version,
2704 'layer_in_project' : ProjectLayer.objects.filter(project_id=pid,layercommit=layerid).count(),
2705 'machines': machines,
2706 'targets': targets,
2707 'total_targets': Recipe.objects.filter(layer_version=layer_version).count(),
2708
2709 'total_machines': Machine.objects.filter(layer_version=layer_version).count(),
2710 }
2711 return render(request, template, context)
2712
2713 def get_project_configvars_context(): 2667 def get_project_configvars_context():
2714 # Vars managed outside of this view 2668 # Vars managed outside of this view
2715 vars_managed = { 2669 vars_managed = {
@@ -3250,9 +3204,6 @@ else:
3250 def importlayer(request): 3204 def importlayer(request):
3251 return render(request, 'landing_not_managed.html') 3205 return render(request, 'landing_not_managed.html')
3252 3206
3253 def layerdetails(request, layerid):
3254 return render(request, 'landing_not_managed.html')
3255
3256 def projectconf(request, pid): 3207 def projectconf(request, pid):
3257 return render(request, 'landing_not_managed.html') 3208 return render(request, 'landing_not_managed.html')
3258 3209
diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py
index 8d449193af..b5dfbbc039 100644
--- a/bitbake/lib/toaster/toastergui/widgets.py
+++ b/bitbake/lib/toaster/toastergui/widgets.py
@@ -26,7 +26,7 @@ from django.core import serializers
26from django.core.cache import cache 26from django.core.cache import cache
27from django.core.paginator import Paginator, EmptyPage 27from django.core.paginator import Paginator, EmptyPage
28from django.db.models import Q 28from django.db.models import Q
29from orm.models import Project, ProjectLayer 29from orm.models import Project, ProjectLayer, Layer_Version
30from django.template import Context, Template 30from django.template import Context, Template
31from django.core.serializers.json import DjangoJSONEncoder 31from django.core.serializers.json import DjangoJSONEncoder
32from django.core.exceptions import FieldError 32from django.core.exceptions import FieldError
@@ -43,9 +43,13 @@ class ToasterTemplateView(TemplateView):
43 def get_context_data(self, **kwargs): 43 def get_context_data(self, **kwargs):
44 context = super(ToasterTemplateView, self).get_context_data(**kwargs) 44 context = super(ToasterTemplateView, self).get_context_data(**kwargs)
45 if 'pid' in kwargs: 45 if 'pid' in kwargs:
46 context['project'] = Project.objects.get(pk=kwargs['pid']) 46 context['project'] = Project.objects.get(pk=kwargs['pid'])
47
48 context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project']))
49
50 if 'layerid' in kwargs:
51 context['layerversion'] = Layer_Version.objects.get(pk=kwargs['layerid'])
47 52
48 context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project']))
49 return context 53 return context
50 54
51 55
@@ -269,13 +273,6 @@ class ToasterTable(View):
269 'rows' : [], 273 'rows' : [],
270 } 274 }
271 275
272 # Flatten all the fields we will need into one list
273 fields = []
274 for col in self.columns:
275 if type(col['field_name']) is list:
276 fields.extend(col['field_name'])
277 else:
278 fields.append(col['field_name'])
279 276
280 try: 277 try:
281 for row in page.object_list: 278 for row in page.object_list: