summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/toastergui')
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/layerBtn.js3
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js103
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/recipedetails.js3
-rw-r--r--bitbake/lib/toaster/toastergui/templates/basebuildpage.html207
-rw-r--r--bitbake/lib/toaster/toastergui/templates/editcustomimage_modal.html23
-rw-r--r--bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html28
-rw-r--r--bitbake/lib/toaster/toastergui/templatetags/queryset_to_list_filter.py26
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py7
8 files changed, 304 insertions, 96 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/layerBtn.js b/bitbake/lib/toaster/toastergui/static/js/layerBtn.js
index aa43284396..259271df33 100644
--- a/bitbake/lib/toaster/toastergui/static/js/layerBtn.js
+++ b/bitbake/lib/toaster/toastergui/static/js/layerBtn.js
@@ -76,7 +76,8 @@ function layerBtnsInit() {
76 if (imgCustomModal.length == 0) 76 if (imgCustomModal.length == 0)
77 throw("Modal new-custom-image not found"); 77 throw("Modal new-custom-image not found");
78 78
79 imgCustomModal.data('recipe', $(this).data('recipe')); 79 var recipe = {id: $(this).data('recipe'), name: null}
80 newCustomImageModalSetRecipes([recipe]);
80 imgCustomModal.modal('show'); 81 imgCustomModal.modal('show');
81 }); 82 });
82} 83}
diff --git a/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js b/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js
index 98e87f4a6b..1ae0d34e90 100644
--- a/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js
+++ b/bitbake/lib/toaster/toastergui/static/js/newcustomimage_modal.js
@@ -1,33 +1,59 @@
1"use strict"; 1"use strict";
2 2
3/* Used for the newcustomimage_modal actions */ 3/*
4Used for the newcustomimage_modal actions
5
6The .data('recipe') value on the outer element determines which
7recipe ID is used as the basis for the new custom image recipe created via
8this modal.
9
10Use newCustomImageModalSetRecipes() to set the recipes available as a base
11for the new custom image. This will manage the addition of radio buttons
12to select the base image (or remove the radio buttons, if there is only a
13single base image available).
14*/
4function newCustomImageModalInit(){ 15function newCustomImageModalInit(){
5 16
6 var newCustomImgBtn = $("#create-new-custom-image-btn"); 17 var newCustomImgBtn = $("#create-new-custom-image-btn");
7 var imgCustomModal = $("#new-custom-image-modal"); 18 var imgCustomModal = $("#new-custom-image-modal");
8 var invalidNameHelp = $("#invalid-name-help"); 19 var invalidNameHelp = $("#invalid-name-help");
20 var invalidRecipeHelp = $("#invalid-recipe-help");
9 var nameInput = imgCustomModal.find('input'); 21 var nameInput = imgCustomModal.find('input');
10 22
11 var invalidMsg = "Image names cannot contain spaces or capital letters. The only allowed special character is dash (-)."; 23 var invalidNameMsg = "Image names cannot contain spaces or capital letters. The only allowed special character is dash (-).";
12 var duplicateImageMsg = "An image with this name already exists in this project."; 24 var duplicateNameMsg = "An image with this name already exists. Image names must be unique.";
13 var duplicateRecipeMsg = "A non-image recipe with this name already exists."; 25 var invalidBaseRecipeIdMsg = "Please select an image to customise.";
26
27 // capture clicks on radio buttons inside the modal; when one is selected,
28 // set the recipe on the modal
29 imgCustomModal.on("click", "[name='select-image']", function (e) {
30 clearRecipeError();
31
32 var recipeId = $(e.target).attr('data-recipe');
33 imgCustomModal.data('recipe', recipeId);
34 });
14 35
15 newCustomImgBtn.click(function(e){ 36 newCustomImgBtn.click(function(e){
16 e.preventDefault(); 37 e.preventDefault();
17 38
18 var baseRecipeId = imgCustomModal.data('recipe'); 39 var baseRecipeId = imgCustomModal.data('recipe');
19 40
41 if (!baseRecipeId) {
42 showRecipeError(invalidBaseRecipeIdMsg);
43 return;
44 }
45
20 if (nameInput.val().length > 0) { 46 if (nameInput.val().length > 0) {
21 libtoaster.createCustomRecipe(nameInput.val(), baseRecipeId, 47 libtoaster.createCustomRecipe(nameInput.val(), baseRecipeId,
22 function(ret) { 48 function(ret) {
23 if (ret.error !== "ok") { 49 if (ret.error !== "ok") {
24 console.warn(ret.error); 50 console.warn(ret.error);
25 if (ret.error === "invalid-name") { 51 if (ret.error === "invalid-name") {
26 showError(invalidMsg); 52 showNameError(invalidNameMsg);
27 } else if (ret.error === "image-already-exists") { 53 return;
28 showError(duplicateImageMsg); 54 } else if (ret.error === "already-exists") {
29 } else if (ret.error === "recipe-already-exists") { 55 showNameError(duplicateNameMsg);
30 showError(duplicateRecipeMsg); 56 return;
31 } 57 }
32 } else { 58 } else {
33 imgCustomModal.modal('hide'); 59 imgCustomModal.modal('hide');
@@ -37,12 +63,21 @@ function newCustomImageModalInit(){
37 } 63 }
38 }); 64 });
39 65
40 function showError(text){ 66 function showNameError(text){
41 invalidNameHelp.text(text); 67 invalidNameHelp.text(text);
42 invalidNameHelp.show(); 68 invalidNameHelp.show();
43 nameInput.parent().addClass('error'); 69 nameInput.parent().addClass('error');
44 } 70 }
45 71
72 function showRecipeError(text){
73 invalidRecipeHelp.text(text);
74 invalidRecipeHelp.show();
75 }
76
77 function clearRecipeError(){
78 invalidRecipeHelp.hide();
79 }
80
46 nameInput.on('keyup', function(){ 81 nameInput.on('keyup', function(){
47 if (nameInput.val().length === 0){ 82 if (nameInput.val().length === 0){
48 newCustomImgBtn.prop("disabled", true); 83 newCustomImgBtn.prop("disabled", true);
@@ -50,7 +85,7 @@ function newCustomImageModalInit(){
50 } 85 }
51 86
52 if (nameInput.val().search(/[^a-z|0-9|-]/) != -1){ 87 if (nameInput.val().search(/[^a-z|0-9|-]/) != -1){
53 showError(invalidMsg); 88 showNameError(invalidNameMsg);
54 newCustomImgBtn.prop("disabled", true); 89 newCustomImgBtn.prop("disabled", true);
55 nameInput.parent().addClass('error'); 90 nameInput.parent().addClass('error');
56 } else { 91 } else {
@@ -60,3 +95,49 @@ function newCustomImageModalInit(){
60 } 95 }
61 }); 96 });
62} 97}
98
99// Set the image recipes which can used as the basis for the custom
100// image recipe the user is creating
101//
102// baseRecipes: a list of one or more recipes which can be
103// used as the base for the new custom image recipe in the format:
104// [{'id': <recipe ID>, 'name': <recipe name>'}, ...]
105//
106// if recipes is a single recipe, just show the text box to set the
107// name for the new custom image; if recipes contains multiple recipe objects,
108// show a set of radio buttons so the user can decide which to use as the
109// basis for the new custom image
110function newCustomImageModalSetRecipes(baseRecipes) {
111 var imgCustomModal = $("#new-custom-image-modal");
112 var imageSelector = $('#new-custom-image-modal [data-role="image-selector"]');
113 var imageSelectRadiosContainer = $('#new-custom-image-modal [data-role="image-selector-radios"]');
114
115 if (baseRecipes.length === 1) {
116 // hide the radio button container
117 imageSelector.hide();
118
119 // remove any radio buttons + labels
120 imageSelector.remove('[data-role="image-radio"]');
121
122 // set the single recipe ID on the modal as it's the only one
123 // we can build from
124 imgCustomModal.data('recipe', baseRecipes[0].id);
125 }
126 else {
127 // add radio buttons; note that the handlers for the radio buttons
128 // are set in newCustomImageModalInit via event delegation
129 for (var i = 0; i < baseRecipes.length; i++) {
130 var recipe = baseRecipes[i];
131 imageSelectRadiosContainer.append(
132 '<label class="radio" data-role="image-radio">' +
133 recipe.name +
134 '<input type="radio" class="form-control" name="select-image" ' +
135 'data-recipe="' + recipe.id + '">' +
136 '</label>'
137 );
138 }
139
140 // show the radio button container
141 imageSelector.show();
142 }
143}
diff --git a/bitbake/lib/toaster/toastergui/static/js/recipedetails.js b/bitbake/lib/toaster/toastergui/static/js/recipedetails.js
index d5f9eacdce..604db5f037 100644
--- a/bitbake/lib/toaster/toastergui/static/js/recipedetails.js
+++ b/bitbake/lib/toaster/toastergui/static/js/recipedetails.js
@@ -9,7 +9,8 @@ function recipeDetailsPageInit(ctx){
9 if (imgCustomModal.length === 0) 9 if (imgCustomModal.length === 0)
10 throw("Modal new-custom-image not found"); 10 throw("Modal new-custom-image not found");
11 11
12 imgCustomModal.data('recipe', $(this).data('recipe')); 12 var recipe = {id: $(this).data('recipe'), name: null}
13 newCustomImageModalSetRecipes([recipe]);
13 imgCustomModal.modal('show'); 14 imgCustomModal.modal('show');
14 }); 15 });
15 16
diff --git a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html
index ff9433eee7..4a8e2a7abd 100644
--- a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html
+++ b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html
@@ -1,90 +1,149 @@
1{% extends "base.html" %} 1{% extends "base.html" %}
2{% load projecttags %} 2{% load projecttags %}
3{% load project_url_tag %} 3{% load project_url_tag %}
4{% load queryset_to_list_filter %}
4{% load humanize %} 5{% load humanize %}
5{% block pagecontent %} 6{% block pagecontent %}
7 <!-- breadcrumbs -->
8 <div class="section">
9 <ul class="breadcrumb" id="breadcrumb">
10 <li><a href="{% project_url build.project %}">{{build.project.name}}</a></li>
11 {% if not build.project.is_default %}
12 <li><a href="{% url 'projectbuilds' build.project.id %}">Builds</a></li>
13 {% endif %}
14 <li>
15 {% block parentbreadcrumb %}
16 <a href="{%url 'builddashboard' build.pk%}">
17 {{build.get_sorted_target_list.0.target}} {% if build.target_set.all.count > 1 %}(+{{build.target_set.all.count|add:"-1"}}){% endif %} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})
18 </a>
19 {% endblock %}
20 </li>
21 {% block localbreadcrumb %}{% endblock %}
22 </ul>
23 <script>
24 $( function () {
25 $('#breadcrumb > li').append('<span class="divider">&rarr;</span>');
26 $('#breadcrumb > li:last').addClass("active");
27 $('#breadcrumb > li:last > span').remove();
28 });
29 </script>
30 </div>
31
32 <div class="row-fluid">
33 <!-- begin left sidebar container -->
34 <div id="nav" class="span2">
35 <ul class="nav nav-list well">
36 <li
37 {% if request.resolver_match.url_name == 'builddashboard' %}
38 class="active"
39 {% endif %} >
40 <a class="nav-parent" href="{% url 'builddashboard' build.pk %}">Build summary</a>
41 </li>
42 {% if build.target_set.all.0.is_image and build.outcome == 0 %}
43 <li class="nav-header">Images</li>
44 {% block nav-target %}
45 {% for t in build.get_sorted_target_list %}
46 <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
47 {% endfor %}
48 {% endblock %}
49 {% endif %}
50 <li class="nav-header">Build</li>
51 {% block nav-configuration %}
52 <li><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
53 {% endblock %}
54 {% block nav-tasks %}
55 <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
56 {% endblock %}
57 {% block nav-recipes %}
58 <li><a href="{% url 'recipes' build.pk %}">Recipes</a></li>
59 {% endblock %}
60 {% block nav-packages %}
61 <li><a href="{% url 'packages' build.pk %}">Packages</a></li>
62 {% endblock %}
63 <li class="nav-header">Performance</li>
64 {% block nav-buildtime %}
65 <li><a href="{% url 'buildtime' build.pk %}">Time</a></li>
66 {% endblock %}
67 {% block nav-cputime %}
68 <li><a href="{% url 'cputime' build.pk %}">CPU usage</a></li>
69 {% endblock %}
70 {% block nav-diskio %}
71 <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
72 {% endblock %}
6 73
74 <li class="divider"></li>
7 75
8 <div class=""> 76 <li>
9<!-- Breadcrumbs --> 77 <p class="navbar-btn">
10 <div class="section"> 78 <a class="btn btn-block" href="{% url 'build_artifact' build.id 'cookerlog' build.id %}">
11 <ul class="breadcrumb" id="breadcrumb"> 79 Download build log
12 <li><a href="{% project_url build.project %}">{{build.project.name}}</a></li>
13 {% if not build.project.is_default %}
14 <li><a href="{% url 'projectbuilds' build.project.id %}">Builds</a></li>
15 {% endif %}
16 <li>
17 {% block parentbreadcrumb %}
18 <a href="{%url 'builddashboard' build.pk%}">
19 {{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+{{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})
20 </a> 80 </a>
21 {% endblock %} 81 </p>
22 </li> 82 </li>
23 {% block localbreadcrumb %}{% endblock %}
24 </ul>
25 <script>
26 $( function () {
27 $('#breadcrumb > li').append('<span class="divider">&rarr;</span>');
28 $('#breadcrumb > li:last').addClass("active");
29 $('#breadcrumb > li:last > span').remove();
30 });
31 </script>
32 </div>
33 83
34 <div class="row-fluid"> 84 <li>
85 <!-- edit custom image built during this build -->
86 <p class="navbar-btn" data-role="edit-custom-image-trigger">
87 <button class="btn btn-block">Edit custom image</button>
88 </p>
89 {% include 'editcustomimage_modal.html' %}
90 <script>
91 $(document).ready(function () {
92 var editableCustomImageRecipes = {{ build.get_custom_image_recipes | queryset_to_list:"id,name" | json }};
35 93
36 <!-- begin left sidebar container --> 94 // edit custom image which was built during this build
37 <div id="nav" class="span2"> 95 var editCustomImageModal = $('#edit-custom-image-modal');
38 <ul class="nav nav-list well"> 96 var editCustomImageTrigger = $('[data-role="edit-custom-image-trigger"]');
39 <li
40 {% if request.resolver_match.url_name == 'builddashboard' %}
41 class="active"
42 {% endif %} >
43 <a class="nav-parent" href="{% url 'builddashboard' build.pk %}">Build summary</a>
44 </li>
45 {% if build.target_set.all.0.is_image and build.outcome == 0 %}
46 <li class="nav-header">Images</li>
47 {% block nav-target %}
48 {% for t in build.get_sorted_target_list %}
49 <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
50 {% endfor %}
51 {% endblock %}
52 {% endif %}
53 <li class="nav-header">Build</li>
54 {% block nav-configuration %}
55 <li><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
56 {% endblock %}
57 {% block nav-tasks %}
58 <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
59 {% endblock %}
60 {% block nav-recipes %}
61 <li><a href="{% url 'recipes' build.pk %}">Recipes</a></li>
62 {% endblock %}
63 {% block nav-packages %}
64 <li><a href="{% url 'packages' build.pk %}">Packages</a></li>
65 {% endblock %}
66 <li class="nav-header">Performance</li>
67 {% block nav-buildtime %}
68 <li><a href="{% url 'buildtime' build.pk %}">Time</a></li>
69 {% endblock %}
70 {% block nav-cputime %}
71 <li><a href="{% url 'cputime' build.pk %}">CPU time</a></li>
72 {% endblock %}
73 {% block nav-diskio %}
74 <li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
75 {% endblock %}
76 </ul>
77 </div>
78 <!-- end left sidebar container -->
79 97
80 <!-- Begin right container --> 98 editCustomImageTrigger.click(function () {
81 {% block buildinfomain %}{% endblock %} 99 // if there is a single editable custom image, go direct to the edit
82 <!-- End right container --> 100 // page for it; if there are multiple editable custom images, show
101 // dialog to select one of them for editing
83 102
103 // single editable custom image
84 104
85 </div> 105 // multiple editable custom images
86 </div> 106 editCustomImageModal.modal('show');
107 });
108 });
109 </script>
110 </li>
87 111
112 <li>
113 <!-- new custom image from image recipe in this build -->
114 <p class="navbar-btn" data-role="new-custom-image-trigger">
115 <button class="btn btn-block">New custom image</button>
116 </p>
117 {% include 'newcustomimage_modal.html' %}
118 <script>
119 // imageRecipes includes both custom image recipes and built-in
120 // image recipes, any of which can be used as the basis for a
121 // new custom image
122 var imageRecipes = {{ build.get_image_recipes | queryset_to_list:"id,name" | json }};
88 123
89{% endblock %} 124 $(document).ready(function () {
125 var newCustomImageModal = $('#new-custom-image-modal');
126 var newCustomImageTrigger = $('[data-role="new-custom-image-trigger"]');
90 127
128 // show create new custom image modal to select an image built
129 // during this build as the basis for the custom recipe
130 newCustomImageTrigger.click(function () {
131 if (!imageRecipes.length) {
132 return;
133 }
134 newCustomImageModalSetRecipes(imageRecipes);
135 newCustomImageModal.modal('show');
136 });
137 });
138 </script>
139 </li>
140 </ul>
141
142 </div>
143 <!-- end left sidebar container -->
144
145 <!-- begin right container -->
146 {% block buildinfomain %}{% endblock %}
147 <!-- end right container -->
148 </div>
149{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/templates/editcustomimage_modal.html b/bitbake/lib/toaster/toastergui/templates/editcustomimage_modal.html
new file mode 100644
index 0000000000..fd998f63eb
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/editcustomimage_modal.html
@@ -0,0 +1,23 @@
1<!--
2modal dialog shown on the build dashboard, for editing an existing custom image
3-->
4<div class="modal hide fade in" aria-hidden="false" id="edit-custom-image-modal">
5 <div class="modal-header">
6 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
7 <h3>Select custom image to edit</h3>
8 </div>
9 <div class="modal-body">
10 <div class="row-fluid">
11 <span class="help-block">
12 Explanation of what this modal is for
13 </span>
14 </div>
15 <div class="control-group controls">
16 <input type="text" class="huge" placeholder="input box" required>
17 <span class="help-block error" style="display:none">Error text</span>
18 </div>
19 </div>
20 <div class="modal-footer">
21 <button class="btn btn-primary btn-large" disabled>Action</button>
22 </div>
23</div>
diff --git a/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html b/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html
index b1b5148c08..caeb302352 100644
--- a/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html
+++ b/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html
@@ -15,18 +15,34 @@
15<div class="modal hide fade in" id="new-custom-image-modal" aria-hidden="false"> 15<div class="modal hide fade in" id="new-custom-image-modal" aria-hidden="false">
16 <div class="modal-header"> 16 <div class="modal-header">
17 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 17 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
18 <h3>Name your custom image</h3> 18 <h3>New custom image</h3>
19 </div> 19 </div>
20
20 <div class="modal-body"> 21 <div class="modal-body">
22 <!--
23 this container is visible if there are multiple image recipes which could
24 be used as a basis for the new custom image; radio buttons are added to it
25 via newCustomImageModalSetRecipes() as required
26 -->
27 <div data-role="image-selector" style="display:none;">
28 <h4>Which image do you want to customise?</h4>
29 <div data-role="image-selector-radios"></div>
30 <span class="help-block error" id="invalid-recipe-help" style="display:none"></span>
31 <div class="air"></div>
32 </div>
33
34 <h4>Name your custom image</h4>
35
21 <div class="row-fluid"> 36 <div class="row-fluid">
22 <span class="help-block span8">Image names must be unique. They should not contain spaces or capital letters, and the only allowed special character is dash (-).<p></p> 37 <span class="help-block span8">Image names must be unique. They should not contain spaces or capital letters, and the only allowed special character is dash (-).<p></p>
23 </span></div> 38 </span></div>
24 <div class="control-group controls"> 39 <div class="control-group controls">
25 <input type="text" class="huge" placeholder="Type the custom image name" required> 40 <input type="text" class="huge" placeholder="Type the custom image name" required>
26 <span class="help-block error" id="invalid-name-help" style="display:none"></span> 41 <span class="help-block error" id="invalid-name-help" style="display:none"></span>
27 </div>
28 </div>
29 <div class="modal-footer">
30 <button id="create-new-custom-image-btn" class="btn btn-primary btn-large" data-original-title="" title="" disabled>Create custom image</button>
31 </div> 42 </div>
43 </div>
44
45 <div class="modal-footer">
46 <button id="create-new-custom-image-btn" class="btn btn-primary btn-large" data-original-title="" title="" disabled>Create custom image</button>
47 </div>
32</div> 48</div>
diff --git a/bitbake/lib/toaster/toastergui/templatetags/queryset_to_list_filter.py b/bitbake/lib/toaster/toastergui/templatetags/queryset_to_list_filter.py
new file mode 100644
index 0000000000..dfc094b591
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templatetags/queryset_to_list_filter.py
@@ -0,0 +1,26 @@
1from django import template
2import json
3
4register = template.Library()
5
6def queryset_to_list(queryset, fields):
7 """
8 Convert a queryset to a list; fields can be set to a comma-separated
9 string of fields for each record included in the resulting list; if
10 omitted, all fields are included for each record, e.g.
11
12 {{ queryset | queryset_to_list:"id,name" }}
13
14 will return a list like
15
16 [{'id': 1, 'name': 'foo'}, ...]
17
18 (providing queryset has id and name fields)
19 """
20 if fields:
21 fields_list = [field.strip() for field in fields.split(',')]
22 return list(queryset.values(*fields_list))
23 else:
24 return list(queryset.values())
25
26register.filter('queryset_to_list', queryset_to_list)
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 9744f4efaf..942dc31ae9 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -1257,7 +1257,10 @@ def recipes(request, build_id):
1257 if retval: 1257 if retval:
1258 return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id) 1258 return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id)
1259 (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe) 1259 (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe)
1260 queryset = Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)).select_related("layer_version", "layer_version__layer") 1260
1261 build = Build.objects.get(pk=build_id)
1262
1263 queryset = build.get_recipes()
1261 queryset = _get_queryset(Recipe, queryset, filter_string, search_term, ordering_string, 'name') 1264 queryset = _get_queryset(Recipe, queryset, filter_string, search_term, ordering_string, 'name')
1262 1265
1263 recipes = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1)) 1266 recipes = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1))
@@ -1276,8 +1279,6 @@ def recipes(request, build_id):
1276 revlist.append(recipe_dep) 1279 revlist.append(recipe_dep)
1277 revs[recipe.id] = revlist 1280 revs[recipe.id] = revlist
1278 1281
1279 build = Build.objects.get(pk=build_id)
1280
1281 context = { 1282 context = {
1282 'objectname': 'recipes', 1283 'objectname': 'recipes',
1283 'build': build, 1284 'build': build,