diff options
Diffstat (limited to 'bitbake')
12 files changed, 610 insertions, 476 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/base.js b/bitbake/lib/toaster/toastergui/static/js/base.js index 6fd77ea457..0fb1f8b6bf 100644 --- a/bitbake/lib/toaster/toastergui/static/js/base.js +++ b/bitbake/lib/toaster/toastergui/static/js/base.js | |||
@@ -6,13 +6,20 @@ function basePageInit(ctx) { | |||
6 | var newBuildTargetInput; | 6 | var newBuildTargetInput; |
7 | var newBuildTargetBuildBtn; | 7 | var newBuildTargetBuildBtn; |
8 | 8 | ||
9 | /* initially the current project is used unless overridden by the new build | ||
10 | * button in top right nav | ||
11 | */ | ||
9 | var selectedProject = libtoaster.ctx; | 12 | var selectedProject = libtoaster.ctx; |
13 | |||
10 | var selectedTarget; | 14 | var selectedTarget; |
11 | 15 | ||
12 | var newBuildProjectInput = $("#new-build-button #project-name-input"); | 16 | var newBuildProjectInput = $("#new-build-button #project-name-input"); |
13 | var newBuildProjectSaveBtn = $("#new-build-button #save-project-button"); | 17 | var newBuildProjectSaveBtn = $("#new-build-button #save-project-button"); |
14 | 18 | ||
15 | $("#config-nav .nav li a").each(function(){ | 19 | |
20 | _checkProjectBuildable(); | ||
21 | |||
22 | $("#project-topbar .nav li a").each(function(){ | ||
16 | if (window.location.pathname === $(this).attr('href')) | 23 | if (window.location.pathname === $(this).attr('href')) |
17 | $(this).parent().addClass('active'); | 24 | $(this).parent().addClass('active'); |
18 | else | 25 | else |
@@ -26,7 +33,7 @@ function basePageInit(ctx) { | |||
26 | }); | 33 | }); |
27 | } | 34 | } |
28 | 35 | ||
29 | /* Hide the button if we're on the project,newproject or importlyaer page | 36 | /* Hide the button if we're on the project,newproject or importlyaer page |
30 | * or if there are no projects yet defined | 37 | * or if there are no projects yet defined |
31 | * only show if there isn't already a build-target-input already | 38 | * only show if there isn't already a build-target-input already |
32 | */ | 39 | */ |
@@ -37,8 +44,8 @@ function basePageInit(ctx) { | |||
37 | newBuildTargetInput = $("#new-build-button .build-target-input"); | 44 | newBuildTargetInput = $("#new-build-button .build-target-input"); |
38 | newBuildTargetBuildBtn = $("#new-build-button .build-button"); | 45 | newBuildTargetBuildBtn = $("#new-build-button .build-button"); |
39 | 46 | ||
40 | newBuildButton.show(); | ||
41 | _setupNewBuildButton(); | 47 | _setupNewBuildButton(); |
48 | newBuildButton.show(); | ||
42 | } else if ($(".build-target-input").length > 0) { | 49 | } else if ($(".build-target-input").length > 0) { |
43 | newBuildTargetInput = $("#project-topbar .build-target-input"); | 50 | newBuildTargetInput = $("#project-topbar .build-target-input"); |
44 | newBuildTargetBuildBtn = $("#project-topbar .build-button"); | 51 | newBuildTargetBuildBtn = $("#project-topbar .build-button"); |
@@ -52,9 +59,35 @@ function basePageInit(ctx) { | |||
52 | $('#project .icon-pencil').hide(); | 59 | $('#project .icon-pencil').hide(); |
53 | } | 60 | } |
54 | 61 | ||
62 | libtoaster.makeTypeahead(newBuildTargetInput, selectedProject.projectTargetsUrl, { format: "json" }, function (item) { | ||
63 | /* successfully selected a target */ | ||
64 | selectedTarget = item; | ||
65 | }); | ||
55 | 66 | ||
56 | _checkProjectBuildable(); | 67 | newBuildTargetInput.on('input', function () { |
68 | if ($(this).val().length === 0) { | ||
69 | newBuildTargetBuildBtn.attr("disabled", "disabled"); | ||
70 | } else { | ||
71 | newBuildTargetBuildBtn.removeAttr("disabled"); | ||
72 | } | ||
73 | }); | ||
74 | |||
75 | newBuildTargetBuildBtn.click(function (e) { | ||
76 | e.preventDefault(); | ||
77 | |||
78 | if (!newBuildTargetInput.val()) { | ||
79 | return; | ||
80 | } | ||
57 | 81 | ||
82 | if (!selectedTarget) { | ||
83 | selectedTarget = { name: newBuildTargetInput.val() }; | ||
84 | } | ||
85 | /* Fire off the build */ | ||
86 | libtoaster.startABuild(selectedProject.projectBuildsUrl, | ||
87 | selectedProject.projectId, selectedTarget.name, function(){ | ||
88 | window.location.replace(selectedProject.projectBuildsUrl); | ||
89 | }, null); | ||
90 | }); | ||
58 | 91 | ||
59 | function _checkProjectBuildable() { | 92 | function _checkProjectBuildable() { |
60 | if (selectedProject.projectId === undefined) { | 93 | if (selectedProject.projectId === undefined) { |
@@ -74,21 +107,12 @@ function basePageInit(ctx) { | |||
74 | /* we can build this project; enable input fields */ | 107 | /* we can build this project; enable input fields */ |
75 | newBuildTargetInput.prop("disabled", false); | 108 | newBuildTargetInput.prop("disabled", false); |
76 | newBuildTargetBuildBtn.prop("disabled", false); | 109 | newBuildTargetBuildBtn.prop("disabled", false); |
77 | 110 | } | |
78 | libtoaster.makeTypeahead(newBuildTargetInput, selectedProject.projectTargetsUrl, { format: "json" }, function (item) { | ||
79 | /* successfully selected a target */ | ||
80 | selectedProject.projectPageUrl = item.projectPageUrl; | ||
81 | selectedProject.projectName = item.name; | ||
82 | selectedProject.projectId = item.id; | ||
83 | selectedProject.projectBuildsUrl = item.projectBuildsUrl; | ||
84 | }); | ||
85 | |||
86 | } | ||
87 | }, null); | 111 | }, null); |
88 | } | 112 | } |
89 | 113 | ||
114 | /* Setup New build button in the top nav bar */ | ||
90 | function _setupNewBuildButton() { | 115 | function _setupNewBuildButton() { |
91 | /* Setup New build button */ | ||
92 | 116 | ||
93 | /* If we don't have a current project then present the set project | 117 | /* If we don't have a current project then present the set project |
94 | * form. | 118 | * form. |
@@ -98,7 +122,6 @@ function basePageInit(ctx) { | |||
98 | $('#project .icon-pencil').hide(); | 122 | $('#project .icon-pencil').hide(); |
99 | } | 123 | } |
100 | 124 | ||
101 | |||
102 | libtoaster.makeTypeahead(newBuildProjectInput, selectedProject.projectsUrl, { format : "json" }, function (item) { | 125 | libtoaster.makeTypeahead(newBuildProjectInput, selectedProject.projectsUrl, { format : "json" }, function (item) { |
103 | /* successfully selected a project */ | 126 | /* successfully selected a project */ |
104 | newBuildProjectSaveBtn.removeAttr("disabled"); | 127 | newBuildProjectSaveBtn.removeAttr("disabled"); |
@@ -115,40 +138,16 @@ function basePageInit(ctx) { | |||
115 | newBuildProjectSaveBtn.attr("disabled", "disabled"); | 138 | newBuildProjectSaveBtn.attr("disabled", "disabled"); |
116 | }); | 139 | }); |
117 | 140 | ||
118 | newBuildTargetInput.on('input', function () { | ||
119 | if ($(this).val().length === 0) { | ||
120 | newBuildTargetBuildBtn.attr("disabled", "disabled"); | ||
121 | } else { | ||
122 | newBuildTargetBuildBtn.removeAttr("disabled"); | ||
123 | } | ||
124 | }); | ||
125 | |||
126 | newBuildTargetBuildBtn.click(function () { | ||
127 | if (!newBuildTargetInput.val()) { | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | if (!selectedTarget) { | ||
132 | selectedTarget = { name: newBuildTargetInput.val() }; | ||
133 | } | ||
134 | /* fire and forget */ | ||
135 | libtoaster.startABuild(selectedProject.projectBuildsUrl, selectedProject.projectId, selectedTarget.name, null, null); | ||
136 | window.location.replace(selectedProject.projectPageUrl); | ||
137 | }); | ||
138 | 141 | ||
139 | newBuildProjectSaveBtn.click(function () { | 142 | newBuildProjectSaveBtn.click(function () { |
140 | selectedProject.projectId = selectedProject.pk; | 143 | selectedProject.projectId = selectedProject.pk; |
141 | /* Update the typeahead project_id paramater */ | 144 | /* Update the typeahead project_id paramater */ |
142 | _checkProjectBuildable(); | 145 | _checkProjectBuildable(); |
143 | 146 | ||
144 | /* we set the effective context of the page to the currently selected project */ | ||
145 | /* TBD: do we override even if we already have a context project ?? */ | ||
146 | /* TODO: replace global library context with references to the "selected" project */ | ||
147 | |||
148 | /* we can create a target typeahead only after we have a project selected */ | ||
149 | newBuildTargetInput.prop("disabled", false); | 147 | newBuildTargetInput.prop("disabled", false); |
150 | newBuildTargetBuildBtn.prop("disabled", false); | 148 | newBuildTargetBuildBtn.prop("disabled", false); |
151 | 149 | ||
150 | /* Update the typeahead to use the new selectedProject */ | ||
152 | libtoaster.makeTypeahead(newBuildTargetInput, selectedProject.projectTargetsUrl, { format: "json" }, function (item) { | 151 | libtoaster.makeTypeahead(newBuildTargetInput, selectedProject.projectTargetsUrl, { format: "json" }, function (item) { |
153 | /* successfully selected a target */ | 152 | /* successfully selected a target */ |
154 | selectedTarget = item; | 153 | selectedTarget = item; |
diff --git a/bitbake/lib/toaster/toastergui/static/js/importlayer.js b/bitbake/lib/toaster/toastergui/static/js/importlayer.js index 560e25a01c..03274c00f3 100644 --- a/bitbake/lib/toaster/toastergui/static/js/importlayer.js +++ b/bitbake/lib/toaster/toastergui/static/js/importlayer.js | |||
@@ -16,8 +16,6 @@ function importLayerPageInit (ctx) { | |||
16 | var currentLayerDepSelection; | 16 | var currentLayerDepSelection; |
17 | var validLayerName = /^(\w|-)+$/; | 17 | var validLayerName = /^(\w|-)+$/; |
18 | 18 | ||
19 | $("#new-project-button").hide(); | ||
20 | |||
21 | libtoaster.makeTypeahead(layerDepInput, libtoaster.ctx.projectLayersUrl, { include_added: "true" }, function(item){ | 19 | libtoaster.makeTypeahead(layerDepInput, libtoaster.ctx.projectLayersUrl, { include_added: "true" }, function(item){ |
22 | currentLayerDepSelection = item; | 20 | currentLayerDepSelection = item; |
23 | 21 | ||
@@ -154,7 +152,7 @@ function importLayerPageInit (ctx) { | |||
154 | } else { | 152 | } else { |
155 | /* Success layer import now go to the project page */ | 153 | /* Success layer import now go to the project page */ |
156 | $.cookie('layer-imported-alert', JSON.stringify(data), { path: '/'}); | 154 | $.cookie('layer-imported-alert', JSON.stringify(data), { path: '/'}); |
157 | window.location.replace(libtoaster.ctx.projectPageUrl+'#/layerimported'); | 155 | window.location.replace(libtoaster.ctx.projectPageUrl+'?notify=layer-imported'); |
158 | } | 156 | } |
159 | }, | 157 | }, |
160 | error: function (data) { | 158 | error: function (data) { |
diff --git a/bitbake/lib/toaster/toastergui/static/js/layerdetails.js b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js index 291ed98c34..be6bbcd20f 100644 --- a/bitbake/lib/toaster/toastergui/static/js/layerdetails.js +++ b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js | |||
@@ -16,14 +16,15 @@ function layerDetailsPageInit (ctx) { | |||
16 | }); | 16 | }); |
17 | 17 | ||
18 | $(".breadcrumb li:first a").click(function(e){ | 18 | $(".breadcrumb li:first a").click(function(e){ |
19 | e.preventDefault(); | ||
19 | /* By default this link goes to the project configuration page. However | 20 | /* By default this link goes to the project configuration page. However |
20 | * if we have some builds we go there instead of the default href | 21 | * if we have some builds we go there instead of the default href |
21 | */ | 22 | */ |
22 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ | 23 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ |
23 | if (prjInfo.builds && prjInfo.builds.length > 0) { | 24 | if (prjInfo.builds && prjInfo.builds.length > 0) { |
24 | window.location.replace(libtoaster.ctx.projectBuildsUrl); | 25 | window.location.replace(libtoaster.ctx.projectBuildsUrl); |
25 | e.preventDefault(); | 26 | } else { |
26 | return; | 27 | window.location.replace(libtoaster.ctx.projectPageUrl); |
27 | } | 28 | } |
28 | }); | 29 | }); |
29 | }); | 30 | }); |
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js index afd665ca99..079bbcb0b8 100644 --- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js +++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js | |||
@@ -79,11 +79,12 @@ var libtoaster = (function (){ | |||
79 | data: data, | 79 | data: data, |
80 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, | 80 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, |
81 | success: function (_data) { | 81 | success: function (_data) { |
82 | /* No proper reponse YOCTO #7995 | ||
82 | if (_data.error !== "ok") { | 83 | if (_data.error !== "ok") { |
83 | console.warn(_data.error); | 84 | console.warn(_data.error); |
84 | } else { | 85 | } else { */ |
85 | if (onsuccess !== undefined) onsuccess(_data); | 86 | if (onsuccess !== undefined) onsuccess(_data); |
86 | } | 87 | // } |
87 | }, | 88 | }, |
88 | error: function (_data) { | 89 | error: function (_data) { |
89 | console.warn("Call failed"); | 90 | console.warn("Call failed"); |
@@ -180,7 +181,15 @@ var libtoaster = (function (){ | |||
180 | if (onFail !== undefined) | 181 | if (onFail !== undefined) |
181 | onFail(data); | 182 | onFail(data); |
182 | } else { | 183 | } else { |
183 | onSuccess(data.layerdeps); | 184 | var deps = {}; |
185 | /* Filter out layer dep ids which are in the | ||
186 | * project already. | ||
187 | */ | ||
188 | deps.list = data.layerdeps.list.filter(function(layerObj){ | ||
189 | return (data.projectlayers.lastIndexOf(layerObj.id) < 0); | ||
190 | }); | ||
191 | |||
192 | onSuccess(deps); | ||
184 | } | 193 | } |
185 | }, function() { | 194 | }, function() { |
186 | console.log("E: Failed to make request"); | 195 | console.log("E: Failed to make request"); |
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectpage.js b/bitbake/lib/toaster/toastergui/static/js/projectpage.js new file mode 100644 index 0000000000..b7cb074f11 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/static/js/projectpage.js | |||
@@ -0,0 +1,429 @@ | |||
1 | "use strict"; | ||
2 | |||
3 | function projectPageInit(ctx) { | ||
4 | |||
5 | var layerAddInput = $("#layer-add-input"); | ||
6 | var layersInPrjList = $("#layers-in-project-list"); | ||
7 | var layerAddBtn = $("#add-layer-btn"); | ||
8 | |||
9 | var machineChangeInput = $("#machine-change-input"); | ||
10 | var machineChangeBtn = $("#machine-change-btn"); | ||
11 | var machineForm = $("#select-machine-form"); | ||
12 | var machineChangeFormToggle = $("#change-machine-toggle"); | ||
13 | var machineNameTitle = $("#project-machine-name"); | ||
14 | var machineChangeCancel = $("#cancel-machine-change"); | ||
15 | |||
16 | var freqBuildBtn = $("#freq-build-btn"); | ||
17 | var freqBuildList = $("#freq-build-list"); | ||
18 | |||
19 | var releaseChangeFormToggle = $("#release-change-toggle"); | ||
20 | var releaseTitle = $("#project-release-title"); | ||
21 | var releaseForm = $("#change-release-form"); | ||
22 | var releaseModal = $("#change-release-modal"); | ||
23 | var cancelReleaseChange = $("#cancel-release-change"); | ||
24 | |||
25 | var currentLayerAddSelection; | ||
26 | var currentMachineAddSelection = {}; | ||
27 | |||
28 | var urlParams = libtoaster.parseUrlParams(); | ||
29 | |||
30 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ | ||
31 | updateProjectLayers(prjInfo.layers); | ||
32 | updateFreqBuildRecipes(prjInfo.freqtargets); | ||
33 | updateProjectRelease(prjInfo.release); | ||
34 | updateProjectReleases(prjInfo.releases, prjInfo.release); | ||
35 | |||
36 | /* If we're receiving a machine set from the url and it's different from | ||
37 | * our current machine then activate set machine sequence. | ||
38 | */ | ||
39 | if (urlParams.hasOwnProperty('setMachine') && | ||
40 | urlParams.setMachine !== prjInfo.machine.name){ | ||
41 | currentMachineAddSelection.name = urlParams.setMachine; | ||
42 | machineChangeBtn.click(); | ||
43 | } else { | ||
44 | updateMachineName(prjInfo.machine.name); | ||
45 | } | ||
46 | |||
47 | /* Now we're really ready show the page */ | ||
48 | $("#project-page").show(); | ||
49 | }); | ||
50 | |||
51 | (function notificationRequest(){ | ||
52 | |||
53 | if (urlParams.hasOwnProperty('notify')){ | ||
54 | switch (urlParams.notify){ | ||
55 | case 'new-project': | ||
56 | $("#project-created-notification").show(); | ||
57 | break; | ||
58 | case 'layer-imported': | ||
59 | layerImportedNotification(); | ||
60 | break; | ||
61 | default: | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | })(); | ||
66 | |||
67 | /* Layer imported notification */ | ||
68 | function layerImportedNotification(){ | ||
69 | var imported = $.cookie("layer-imported-alert"); | ||
70 | var message = "Layer imported"; | ||
71 | |||
72 | if (!imported) | ||
73 | return; | ||
74 | else | ||
75 | imported = JSON.parse(imported); | ||
76 | |||
77 | if (imported.deps_added.length === 0) { | ||
78 | message = "You have imported <strong><a href=\""+imported.imported_layer.layerdetailurl+"\">"+imported.imported_layer.name+"</a></strong> and added it to your project."; | ||
79 | } else { | ||
80 | |||
81 | var links = "<a href=\""+imported.imported_layer.layerdetailurl+"\">"+imported.imported_layer.name+"</a>, "; | ||
82 | |||
83 | imported.deps_added.map (function(item, index){ | ||
84 | links +='<a href="'+item.layerdetailurl+'">'+item.name+'</a>'; | ||
85 | /*If we're at the last element we don't want the trailing comma */ | ||
86 | if (imported.deps_added[index+1] !== undefined) | ||
87 | links += ', '; | ||
88 | }); | ||
89 | |||
90 | /* Length + 1 here to do deps + the imported layer */ | ||
91 | message = 'You have imported <strong><a href="'+imported.imported_layer.layerdetailurl+'">'+imported.imported_layer.name+'</a></strong> and added <strong>'+(imported.deps_added.length+1)+'</strong> layers to your project: <strong>'+links+'</strong>'; | ||
92 | } | ||
93 | |||
94 | libtoaster.showChangeNotification(message); | ||
95 | |||
96 | $.removeCookie("layer-imported-alert", { path: "/"}); | ||
97 | } | ||
98 | |||
99 | /* Add/Rm layer functionality */ | ||
100 | |||
101 | libtoaster.makeTypeahead(layerAddInput, libtoaster.ctx.projectLayersUrl, { include_added: "false" }, function(item){ | ||
102 | currentLayerAddSelection = item; | ||
103 | layerAddBtn.removeAttr("disabled"); | ||
104 | }); | ||
105 | |||
106 | layerAddBtn.click(function(e){ | ||
107 | e.preventDefault(); | ||
108 | var layerObj = currentLayerAddSelection; | ||
109 | |||
110 | addRmLayer(layerObj, true); | ||
111 | /* Reset the text input */ | ||
112 | layerAddInput.val(""); | ||
113 | }); | ||
114 | |||
115 | function addRmLayer(layerObj, add){ | ||
116 | |||
117 | libtoaster.addRmLayer(layerObj, add, function(layerDepsList){ | ||
118 | if (add){ | ||
119 | updateProjectLayers([layerObj]); | ||
120 | updateProjectLayers(layerDepsList); | ||
121 | } | ||
122 | |||
123 | /* Show the alert message */ | ||
124 | var message = libtoaster.makeLayerAddRmAlertMsg(layerObj, layerDepsList, add); | ||
125 | libtoaster.showChangeNotification(message); | ||
126 | }); | ||
127 | } | ||
128 | |||
129 | function updateProjectLayers(layers){ | ||
130 | |||
131 | /* No layers to add */ | ||
132 | if (layers.length === 0){ | ||
133 | updateLayersCount(); | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | for (var i in layers){ | ||
138 | var layerObj = layers[i]; | ||
139 | |||
140 | var projectLayer = $("<li><a></a><span class=\"icon-trash\" data-toggle=\"tooltip\" title=\"Delete\"></span></li>"); | ||
141 | |||
142 | projectLayer.data('layer', layerObj); | ||
143 | projectLayer.children("span").tooltip(); | ||
144 | |||
145 | var link = projectLayer.children("a"); | ||
146 | |||
147 | link.attr("href", layerObj.layerdetailurl); | ||
148 | link.text(layerObj.name); | ||
149 | /* YOCTO #8024 | ||
150 | link.tooltip({title: layerObj.giturl + " | "+ layerObj.branch.name, placement: "right"}); | ||
151 | branch name not accessible sometimes it is revision instead | ||
152 | */ | ||
153 | |||
154 | var trashItem = projectLayer.children("span"); | ||
155 | trashItem.click(function (e) { | ||
156 | e.preventDefault(); | ||
157 | var layerObjToRm = $(this).parent().data('layer'); | ||
158 | |||
159 | addRmLayer(layerObjToRm, false); | ||
160 | |||
161 | $(this).parent().fadeOut(function (){ | ||
162 | $(this).remove(); | ||
163 | updateLayersCount(); | ||
164 | }); | ||
165 | }); | ||
166 | |||
167 | layersInPrjList.append(projectLayer); | ||
168 | |||
169 | updateLayersCount(); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | function updateLayersCount(){ | ||
174 | var count = $("#layers-in-project-list").children().length; | ||
175 | |||
176 | if (count === 0) | ||
177 | $("#no-layers-in-project").fadeIn(); | ||
178 | else | ||
179 | $("#no-layers-in-project").hide(); | ||
180 | |||
181 | $("#project-layers-count").text(count); | ||
182 | |||
183 | return count; | ||
184 | } | ||
185 | |||
186 | /* Frequent builds functionality */ | ||
187 | function updateFreqBuildRecipes(recipes) { | ||
188 | var noMostBuilt = $("#no-most-built"); | ||
189 | |||
190 | if (recipes.length === 0){ | ||
191 | noMostBuilt.show(); | ||
192 | freqBuildBtn.hide(); | ||
193 | } else { | ||
194 | noMostBuilt.hide(); | ||
195 | freqBuildBtn.show(); | ||
196 | } | ||
197 | |||
198 | for (var i in recipes){ | ||
199 | var freqTargetCheck = $('<li><label class="checkbox"><input type="checkbox" /><span class="freq-target-name"></span></label></li>'); | ||
200 | freqTargetCheck.find(".freq-target-name").text(recipes[i]); | ||
201 | freqTargetCheck.find("input").val(recipes[i]); | ||
202 | freqTargetCheck.click(function(){ | ||
203 | if (freqBuildList.find(":checked").length > 0) | ||
204 | freqBuildBtn.removeAttr("disabled"); | ||
205 | else | ||
206 | freqBuildBtn.attr("disabled", "disabled"); | ||
207 | }); | ||
208 | |||
209 | freqBuildList.append(freqTargetCheck); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | freqBuildBtn.click(function(e){ | ||
214 | e.preventDefault(); | ||
215 | |||
216 | var toBuild = ""; | ||
217 | freqBuildList.find(":checked").each(function(){ | ||
218 | toBuild += $(this).val(); | ||
219 | toBuild += " "; | ||
220 | }); | ||
221 | |||
222 | libtoaster.startABuild(libtoaster.ctx.projectBuildsUrl, libtoaster.ctx.projectId, toBuild, function(){ | ||
223 | /* Build started */ | ||
224 | window.location.replace(libtoaster.ctx.projectBuildsUrl); | ||
225 | }, | ||
226 | function(){ | ||
227 | /* Build start failed */ | ||
228 | /* [YOCTO #7995] */ | ||
229 | window.location.replace(libtoaster.ctx.projectBuildsUrl); | ||
230 | }); | ||
231 | }); | ||
232 | |||
233 | |||
234 | /* Change machine functionality */ | ||
235 | |||
236 | machineChangeFormToggle.click(function(){ | ||
237 | machineForm.slideDown(); | ||
238 | machineNameTitle.hide(); | ||
239 | $(this).hide(); | ||
240 | }); | ||
241 | |||
242 | machineChangeCancel.click(function(){ | ||
243 | machineForm.slideUp(function(){ | ||
244 | machineNameTitle.show(); | ||
245 | machineChangeFormToggle.show(); | ||
246 | }); | ||
247 | }); | ||
248 | |||
249 | function updateMachineName(machineName){ | ||
250 | machineChangeInput.val(machineName); | ||
251 | machineNameTitle.text(machineName); | ||
252 | } | ||
253 | |||
254 | libtoaster.makeTypeahead(machineChangeInput, libtoaster.ctx.projectMachinesUrl, { }, function(item){ | ||
255 | currentMachineAddSelection = item; | ||
256 | machineChangeBtn.removeAttr("disabled"); | ||
257 | }); | ||
258 | |||
259 | machineChangeBtn.click(function(e){ | ||
260 | e.preventDefault(); | ||
261 | if (currentMachineAddSelection.name === undefined) | ||
262 | return; | ||
263 | |||
264 | libtoaster.editCurrentProject({ machineName : currentMachineAddSelection.name }, | ||
265 | function(){ | ||
266 | /* Success machine changed */ | ||
267 | updateMachineName(currentMachineAddSelection.name); | ||
268 | machineChangeCancel.click(); | ||
269 | |||
270 | /* Show the alert message */ | ||
271 | var message = $('<span class="lead">You have changed the machine to: <strong><span id="notify-machine-name"></span></strong></span>'); | ||
272 | message.find("#notify-machine-name").text(currentMachineAddSelection.name); | ||
273 | libtoaster.showChangeNotification(message); | ||
274 | }, | ||
275 | function(){ | ||
276 | /* Failed machine changed */ | ||
277 | console.log("failed to change machine"); | ||
278 | }); | ||
279 | }); | ||
280 | |||
281 | |||
282 | /* Change release functionality */ | ||
283 | function updateProjectRelease(release){ | ||
284 | releaseTitle.text(release.description); | ||
285 | } | ||
286 | |||
287 | function updateProjectReleases(releases, current){ | ||
288 | for (var i in releases){ | ||
289 | var releaseOption = $("<option></option>"); | ||
290 | |||
291 | releaseOption.val(releases[i].id); | ||
292 | releaseOption.text(releases[i].description); | ||
293 | releaseOption.data('release', releases[i]); | ||
294 | |||
295 | if (releases[i].id == current.id) | ||
296 | releaseOption.attr("selected", "selected"); | ||
297 | |||
298 | releaseForm.children("select").append(releaseOption); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | releaseChangeFormToggle.click(function(){ | ||
303 | releaseForm.slideDown(); | ||
304 | releaseTitle.hide(); | ||
305 | $(this).hide(); | ||
306 | }); | ||
307 | |||
308 | cancelReleaseChange.click(function(e){ | ||
309 | e.preventDefault(); | ||
310 | releaseForm.slideUp(function(){ | ||
311 | releaseTitle.show(); | ||
312 | releaseChangeFormToggle.show(); | ||
313 | }); | ||
314 | }); | ||
315 | |||
316 | function changeProjectRelease(release, layersToRm){ | ||
317 | libtoaster.editCurrentProject({ projectVersion : release.id }, | ||
318 | function(){ | ||
319 | /* Success */ | ||
320 | /* Update layers list with new layers */ | ||
321 | layersInPrjList.addClass('muted'); | ||
322 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, | ||
323 | function(prjInfo){ | ||
324 | layersInPrjList.children().remove(); | ||
325 | updateProjectLayers(prjInfo.layers); | ||
326 | layersInPrjList.removeClass('muted'); | ||
327 | releaseChangedNotification(release, prjInfo.layers, layersToRm); | ||
328 | }); | ||
329 | updateProjectRelease(release); | ||
330 | cancelReleaseChange.click(); | ||
331 | }); | ||
332 | } | ||
333 | |||
334 | /* Create a notification to show the changes to the layer configuration | ||
335 | * caused by changing a release. | ||
336 | */ | ||
337 | |||
338 | function releaseChangedNotification(release, layers, layersToRm){ | ||
339 | |||
340 | var message; | ||
341 | |||
342 | if (layers.length === 0 && layersToRm.length === 0){ | ||
343 | message = $('<span><span class="lead">You have changed the project release to: <strong><span id="notify-release-name"></span></strong>.'); | ||
344 | message.find("#notify-release-name").text(release.description); | ||
345 | libtoaster.showChangeNotification(message); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | /* Create the whitespace separated list of layers removed */ | ||
350 | var layersDelList = ""; | ||
351 | |||
352 | layersToRm.map(function(layer, i){ | ||
353 | layersDelList += layer.name; | ||
354 | if (layersToRm[i+1] !== undefined) | ||
355 | layersDelList += ', '; | ||
356 | }); | ||
357 | |||
358 | message = $('<span><span class="lead">You have changed the project release to: <strong><span id="notify-release-name"></span></strong>. This has caused the following changes in your project layers:</span><ul id="notify-layers-changed-list"></ul></span>'); | ||
359 | |||
360 | var changedList = message.find("#notify-layers-changed-list"); | ||
361 | |||
362 | message.find("#notify-release-name").text(release.description); | ||
363 | |||
364 | /* Manually construct the list item for changed layers */ | ||
365 | var li = '<li><strong>'+layers.length+'</strong> layers changed to the <strong>'+release.name+'</strong> release: '; | ||
366 | for (var i in layers){ | ||
367 | li += '<a href='+layers[i].layerdetailurl+'>'+layers[i].name+'</a>'; | ||
368 | if (i !== 0) | ||
369 | li += ', '; | ||
370 | } | ||
371 | |||
372 | changedList.append($(li)); | ||
373 | |||
374 | /* Layers removed */ | ||
375 | if (layersToRm && layersToRm.length > 0){ | ||
376 | if (layersToRm.length == 1) | ||
377 | li = '<li><strong>1</strong> layer deleted: '+layersToRm[0].name+'</li>'; | ||
378 | else | ||
379 | li = '<li><strong>'+layersToRm.length+'</strong> layers deleted: '+layersDelList+'</li>'; | ||
380 | |||
381 | changedList.append($(li)); | ||
382 | } | ||
383 | |||
384 | libtoaster.showChangeNotification(message); | ||
385 | } | ||
386 | |||
387 | /* Show the modal dialog which gives the option to remove layers which | ||
388 | * aren't compatible with the proposed release | ||
389 | */ | ||
390 | function showReleaseLayerChangeModal(release, layers){ | ||
391 | var layersToRmList = releaseModal.find("#layers-to-remove-list"); | ||
392 | layersToRmList.text(""); | ||
393 | |||
394 | releaseModal.find(".proposed-release-change-name").text(release.description); | ||
395 | releaseModal.data("layers", layers); | ||
396 | releaseModal.data("release", release); | ||
397 | |||
398 | for (var i in layers){ | ||
399 | layersToRmList.append($("<li></li>").text(layers[i].name)); | ||
400 | } | ||
401 | releaseModal.modal('show'); | ||
402 | } | ||
403 | |||
404 | $("#change-release-btn").click(function(e){ | ||
405 | e.preventDefault(); | ||
406 | |||
407 | var newRelease = releaseForm.find("option:selected").data('release'); | ||
408 | |||
409 | $.getJSON(ctx.typeaheadUrl, | ||
410 | { search: newRelease.id, type: "versionlayers" }, | ||
411 | function(layers) { | ||
412 | if (layers.rows.length === 0){ | ||
413 | /* No layers to change for this release */ | ||
414 | changeProjectRelease(newRelease, []); | ||
415 | } else { | ||
416 | showReleaseLayerChangeModal(newRelease, layers.rows); | ||
417 | } | ||
418 | }); | ||
419 | }); | ||
420 | |||
421 | /* Release change modal accept */ | ||
422 | $("#change-release-and-rm-layers").click(function(){ | ||
423 | var layers = releaseModal.data("layers"); | ||
424 | var release = releaseModal.data("release"); | ||
425 | |||
426 | changeProjectRelease(release, layers); | ||
427 | }); | ||
428 | |||
429 | } | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html index 8def2daf8e..4c6676c6e7 100644 --- a/bitbake/lib/toaster/toastergui/templates/base.html +++ b/bitbake/lib/toaster/toastergui/templates/base.html | |||
@@ -38,6 +38,8 @@ | |||
38 | projectName : {{project.name|json}}, | 38 | projectName : {{project.name|json}}, |
39 | projectTargetsUrl: {% url 'projectavailabletargets' project.id as paturl%}{{paturl|json}}, | 39 | projectTargetsUrl: {% url 'projectavailabletargets' project.id as paturl%}{{paturl|json}}, |
40 | projectBuildsUrl: {% url 'projectbuilds' project.id as pburl %}{{pburl|json}}, | 40 | projectBuildsUrl: {% url 'projectbuilds' project.id as pburl %}{{pburl|json}}, |
41 | projectLayersUrl: {% url 'projectlayers' project.id as plurl %}{{plurl|json}}, | ||
42 | projectMachinesUrl: {% url 'projectmachines' project.id as pmurl %}{{pmurl|json}}, | ||
41 | projectId : {{project.id}}, | 43 | projectId : {{project.id}}, |
42 | {% else %} | 44 | {% else %} |
43 | projectId : undefined, | 45 | projectId : undefined, |
@@ -69,6 +71,11 @@ | |||
69 | Loading <i class="fa-pulse icon-spinner"></i> | 71 | Loading <i class="fa-pulse icon-spinner"></i> |
70 | </div> | 72 | </div> |
71 | 73 | ||
74 | <div id="change-notification" class="alert lead alert-info" style="display:none"> | ||
75 | <button type="button" class="close" id="hide-alert">×</button> | ||
76 | <span id="change-notification-msg"></span> | ||
77 | </div> | ||
78 | |||
72 | <div class="navbar navbar-fixed-top"> | 79 | <div class="navbar navbar-fixed-top"> |
73 | <div class="navbar-inner"> | 80 | <div class="navbar-inner"> |
74 | <div class="container-fluid"> | 81 | <div class="container-fluid"> |
diff --git a/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html b/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html index ac32deac2f..0db06a86da 100644 --- a/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html +++ b/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html | |||
@@ -29,8 +29,6 @@ | |||
29 | <li><a href="{% url 'projecttargets' project.id %}">Recipes</a></li> | 29 | <li><a href="{% url 'projecttargets' project.id %}">Recipes</a></li> |
30 | <li><a href="{% url 'projectmachines' project.id %}">Machines</a></li> | 30 | <li><a href="{% url 'projectmachines' project.id %}">Machines</a></li> |
31 | <li><a href="{% url 'projectlayers' project.id %}">Layers</a></li> | 31 | <li><a href="{% url 'projectlayers' project.id %}">Layers</a></li> |
32 | <li class="nav-header">Actions</li> | ||
33 | <li><a href="{% url 'importlayer' project.id %}">Import layer</a></li> | ||
34 | </ul> | 32 | </ul> |
35 | </div> | 33 | </div> |
36 | <div class="span10"> | 34 | <div class="span10"> |
diff --git a/bitbake/lib/toaster/toastergui/templates/importlayer.html b/bitbake/lib/toaster/toastergui/templates/importlayer.html index d6984bcc9f..bec5f1aa74 100644 --- a/bitbake/lib/toaster/toastergui/templates/importlayer.html +++ b/bitbake/lib/toaster/toastergui/templates/importlayer.html | |||
@@ -1,10 +1,11 @@ | |||
1 | {% extends "baseprojectpage.html" %} | 1 | {% extends "base.html" %} |
2 | {% load projecttags %} | 2 | {% load projecttags %} |
3 | {% load humanize %} | 3 | {% load humanize %} |
4 | {% load static %} | 4 | {% load static %} |
5 | {% block pagecontent %} | ||
5 | 6 | ||
7 | {% include "projecttopbar.html" %} | ||
6 | 8 | ||
7 | {% block projectinfomain %} | ||
8 | 9 | ||
9 | {% if project and project.release %} | 10 | {% if project and project.release %} |
10 | <script src="{% static 'js/layerDepsModal.js' %}"></script> | 11 | <script src="{% static 'js/layerDepsModal.js' %}"></script> |
@@ -24,12 +25,10 @@ | |||
24 | }); | 25 | }); |
25 | </script> | 26 | </script> |
26 | 27 | ||
27 | <h2>Import layer</h2> | 28 | <form class="span11"> |
28 | |||
29 | <form> | ||
30 | <span class="help-block">The layer you are importing must be compatible with <strong>{{project.release.description}}</strong>, which is the release you are using in this project.</span> | ||
31 | <fieldset class="air"> | 29 | <fieldset class="air"> |
32 | <legend>Layer repository information</legend> | 30 | <legend>Layer repository information</legend> |
31 | <span class="help-block">The layer you are importing must be compatible with <strong>{{project.release.description}}</strong>, which is the release you are using in this project.</span> | ||
33 | <div class="alert alert-error" id="import-error" style="display:none"> | 32 | <div class="alert alert-error" id="import-error" style="display:none"> |
34 | <button type="button" class="close" data-dismiss="alert">×</button> | 33 | <button type="button" class="close" data-dismiss="alert">×</button> |
35 | <h3> </h3> | 34 | <h3> </h3> |
@@ -136,5 +135,4 @@ | |||
136 | </div> | 135 | </div> |
137 | 136 | ||
138 | {% endif %} | 137 | {% endif %} |
139 | |||
140 | {% endblock %} | 138 | {% endblock %} |
diff --git a/bitbake/lib/toaster/toastergui/templates/machine_btn.html b/bitbake/lib/toaster/toastergui/templates/machine_btn.html index 54ff5def71..d2cb55bab4 100644 --- a/bitbake/lib/toaster/toastergui/templates/machine_btn.html +++ b/bitbake/lib/toaster/toastergui/templates/machine_btn.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <a href="{% url 'project' extra.pid %}#/machineselect={{data.name}}" class="btn btn-block layer-exists-{{data.layer_version.id}}" style="margin-top: 5px; display:none"> | 1 | <a href="{% url 'project' extra.pid %}?setMachine={{data.name}}" class="btn btn-block layer-exists-{{data.layer_version.id}}" style="margin-top: 5px; display:none"> |
2 | Select machine</a> | 2 | Select machine</a> |
3 | <button class="btn btn-block layerbtn layer-add-{{data.layer_version.id}}" data-layer='{ "id": {{data.layer_version.id}}, "name": "{{data.layer_version.layer.name}}", "layerdetailurl": "{%url 'layerdetails' extra.pid data.layer_version.id %}"}' data-directive="add"> | 3 | <button class="btn btn-block layerbtn layer-add-{{data.layer_version.id}}" data-layer='{ "id": {{data.layer_version.id}}, "name": "{{data.layer_version.layer.name}}", "layerdetailurl": "{%url 'layerdetails' extra.pid data.layer_version.id %}"}' data-directive="add"> |
4 | <i class="icon-plus"></i> | 4 | <i class="icon-plus"></i> |
diff --git a/bitbake/lib/toaster/toastergui/templates/project.html b/bitbake/lib/toaster/toastergui/templates/project.html index 0fbfb599b7..aad79b4860 100644 --- a/bitbake/lib/toaster/toastergui/templates/project.html +++ b/bitbake/lib/toaster/toastergui/templates/project.html | |||
@@ -1,446 +1,130 @@ | |||
1 | {% extends "baseprojectpage.html" %} | 1 | {% extends "baseprojectpage.html" %} |
2 | <!-- | 2 | |
3 | vim: expandtab tabstop=2 | ||
4 | --> | ||
5 | {% load projecttags %} | 3 | {% load projecttags %} |
6 | {% load humanize %} | 4 | {% load humanize %} |
7 | {% load static %} | 5 | {% load static %} |
8 | 6 | ||
9 | |||
10 | {% block projectinfomain %} | 7 | {% block projectinfomain %} |
11 | <script src="{% static "js/angular.min.js" %}"></script> | ||
12 | <script src="{% static "js/angular-animate.min.js" %}"></script> | ||
13 | <script src="{% static "js/angular-cookies.min.js" %}"></script> | ||
14 | <script src="{% static "js/angular-route.min.js" %}"></script> | ||
15 | <script src="{% static "js/angular-sanitize.min.js" %}"></script> | ||
16 | <script src="{% static "js/ui-bootstrap-tpls-0.11.0.js" %}"></script> | ||
17 | 8 | ||
18 | {% if lvs_nos == 0 %} | 9 | <script src="{% static 'js/layerDepsModal.js' %}"></script> |
10 | <script src="{% static 'js/projectpage.js' %}"></script> | ||
11 | <script> | ||
12 | $(document).ready(function (){ | ||
13 | var ctx = { | ||
14 | typeaheadUrl : "{% url 'xhr_datatypeahead' project.id %}", | ||
15 | |||
16 | }; | ||
17 | |||
18 | try { | ||
19 | projectPageInit(ctx); | ||
20 | } catch (e) { | ||
21 | document.write("Sorry, An error has occurred loading this page"); | ||
22 | console.warn(e); | ||
23 | } | ||
24 | }); | ||
25 | </script> | ||
19 | 26 | ||
20 | <div class="page-header"> | 27 | <div id="change-release-modal" class="modal hide fade in" tabindex="-1" role="dialog" aria-labelledby="change-release-modal" aria-hidden="false"> |
21 | <h1> {{ project.name }} </h1> | 28 | <div class="modal-header"> |
29 | <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> | ||
30 | <h3>Changing Yocto Project release to <span class="proposed-release-change-name"></span></h3> | ||
22 | </div> | 31 | </div> |
23 | <div class="alert alert-info lead"> | 32 | <div class="modal-body"> |
24 | <p>Toaster has no layer information. Without layer information, you cannot run builds. To generate layer information you can:</p> | 33 | <p>The following added layers do not exist for <span class="proposed-release-change-name"></span>: </p> |
25 | <ul> | 34 | <ul id="layers-to-remove-list"> |
26 | <li> <a href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html#layer-source">Configure a layer source</a></li> | 35 | </ul> |
27 | <li> <a href="{% url 'importlayer' project.id %}">Import a layer</a></li> | 36 | <p>If you change the Yocto Project release to <span class="proposed-release-change-name"></span>, the above layers will be deleted from your added layers.</p> |
28 | </ul> | ||
29 | </div> | ||
30 | |||
31 | {%else%} | ||
32 | |||
33 | <div id="main" role="main" data-ng-app="project" data-ng-controller="prjCtrl" data-ng-cloak> | ||
34 | |||
35 | <!-- alerts section 1--> | ||
36 | <div data-ng-repeat="a in zone1alerts"> | ||
37 | <div class="alert alert-dismissible lead" role="alert" data-ng-class="a.type"><button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span></button> | ||
38 | <span data-ng-bind-html="a.text"></span> | ||
39 | </div> | ||
40 | </div> | 37 | </div> |
38 | <div class="modal-footer"> | ||
39 | <button id="change-release-and-rm-layers" data-dismiss="modal" type="submit" class="btn btn-primary">Change release and delete layers</button> | ||
40 | <button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button> | ||
41 | </div> | ||
42 | </div> | ||
41 | 43 | ||
42 | <!-- custom templates for ng --> | ||
43 | |||
44 | <style> | ||
45 | .missing-layer { | ||
46 | color: lightgrey; | ||
47 | } | ||
48 | </style> | ||
49 | <script type="text/ng-template" id="recipes_suggestion_details"> | ||
50 | <a> {[match.model.name]} | ||
51 | <span data-ng-class="{'missing-layer':($parent.$parent.$parent.$parent.filterProjectLayerIds().indexOf(match.model.projectcompatible_layer.id) == -1)}"> | ||
52 | [{[match.model.layer_version__layer__name]}] | ||
53 | </span> | ||
54 | </a> | ||
55 | </script> | ||
56 | |||
57 | <script type="text/ng-template" id="machines_suggestion_details"> | ||
58 | <a> {[match.model.name]} <span class="{'missing-layer':(filterProjectLayerIds().indexOf(match.model.layer_version_compatible_id) == -1)}">[{[match.model.layer_version__layer__name]}]</span> </a> | ||
59 | </script> | ||
60 | 44 | ||
61 | <script type="text/ng-template" id="layers_suggestion_details"> | 45 | <div class="row-fluid" id="project-page" style="display:none"> |
62 | <a> {[match.model['layer__name']]} ( {[match.model.layer__vcs_url]} ) </a> | 46 | <div class="span6"> |
63 | </script> | 47 | <div class="well well-transparent" id="machine-section"> |
48 | <h3>Machine</h3> | ||
64 | 49 | ||
50 | <p class="lead"><span id="project-machine-name"></span> <i title="" data-original-title="" id="change-machine-toggle" class="icon-pencil"></i></p> | ||
65 | 51 | ||
52 | <form id="select-machine-form" style="display:none;"> | ||
53 | <div class="alert alert-info"> | ||
54 | <strong>Machine changes have a big impact on build outcome.</strong> You cannot really compare the builds for the new machine with the previous ones. | ||
55 | </div> | ||
66 | 56 | ||
57 | <div class="input-append"> | ||
58 | <input id="machine-change-input" autocomplete="off" value="" data-provide="typeahead" data-minlength="1" data-autocomplete="off" type="text"> | ||
59 | <button id="machine-change-btn" class="btn" type="button">Save</button> <a href="#" id="cancel-machine-change" class="btn btn-link">Cancel</a> | ||
60 | </div> | ||
67 | 61 | ||
68 | <!-- modal dialogs --> | 62 | <p><a href="{% url 'projectmachines' project.id %}" class="link">View compatible machines</a></p> |
69 | <script type="text/ng-template" id="dependencies_modal"> | 63 | </form> |
70 | <div class="modal-header"> | ||
71 | <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> | ||
72 | <h3><span data-ng-bind="layerAddName"></span> dependencies</h3> | ||
73 | </div> | ||
74 | <div class="modal-body"> | ||
75 | <p><strong>{[layerAddName]}</strong> depends on some layers that are not added to your project. Select the ones you want to add:</p> | ||
76 | <ul class="unstyled"> | ||
77 | <li data-ng-repeat="ld in items"> | ||
78 | <label class="checkbox"> | ||
79 | <input type="checkbox" data-ng-model="selectedItems[ld.id]"> {[ld.name]} | ||
80 | </label> | ||
81 | </li> | ||
82 | </ul> | ||
83 | </div> | ||
84 | <div class="modal-footer"> | ||
85 | <button class="btn btn-primary" data-ng-click="ok()">Add layers</button> | ||
86 | <button class="btn" data-ng-click="cancel()">Cancel</button> | ||
87 | </div> | 64 | </div> |
88 | </form> | ||
89 | </script> | ||
90 | 65 | ||
66 | <div class="well well-transparent"> | ||
67 | <h3>Most built recipes</h3> | ||
91 | 68 | ||
92 | <script type="text/ng-template" id="change_version_modal"> | 69 | <div class="alert alert-info" style="display:none" id="no-most-built"> |
93 | <div class="modal-header"> | 70 | <span class="lead">You haven't built any recipes yet</span> |
94 | <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> | ||
95 | <h3>Changing release to {[releaseDescription]}</h3> | ||
96 | </div> | 71 | </div> |
97 | <div class="modal-body"> | ||
98 | <p>The following project layers do not exist for the {[releaseDescription]} release:</p> | ||
99 | <ul> | ||
100 | <li data-ng-repeat="i in items"><span class="layer-info" data-toggle="tooltip" tooltip="{[i.detail]}">{[i.name]}</span></li> | ||
101 | </ul> | ||
102 | <p>If you change the release to {[releaseDescription]}, the above layers will be deleted from your project.</p> | ||
103 | </div> | ||
104 | <div class="modal-footer"> | ||
105 | <button class="btn btn-primary" data-ng-click="ok()">Change release and delete layers</button> | ||
106 | <button class="btn" data-ng-click="cancel()">Cancel</button> | ||
107 | </div> | ||
108 | </script> | ||
109 | |||
110 | <script type="text/ng-template" id="target_display"> | ||
111 | <div data-ng-switch on="t.task.length"> | ||
112 | <div data-ng-switch-when="undefined">{[t.target]}</div> | ||
113 | <div data-ng-switch-default>{[t.target]}:{[t.task]}</div> | ||
114 | </div> | ||
115 | </script> | ||
116 | |||
117 | |||
118 | <!-- latest builds list --> | ||
119 | |||
120 | <a id="buildslist"></a> | ||
121 | <h2 class="air" data-ng-if="builds.length">Latest builds</h2> | ||
122 | <div class="animate-repeat alert" data-ng-repeat="b in builds track by b.id" data-ng-class="{'queued':'alert-info', 'In Progress':'alert-info', 'Succeeded':'alert-success', 'Failed':'alert-error'}[b.status]"> | ||
123 | <div class="row-fluid"> | ||
124 | <switch data-ng-switch="b.status"> | ||
125 | |||
126 | <case data-ng-switch-when="Failed"> | ||
127 | <div class="lead span3"> | ||
128 | <a data-ng-class="{'Succeeded': 'success', 'Failed': 'error'}[b.status]" href="{[b.br_page_url]}"> | ||
129 | <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span> | ||
130 | </a> | ||
131 | </div> | ||
132 | <div class="span2 lead"> | ||
133 | <ngif data-ng-if="b.updated - todaydate > 0"> | ||
134 | {[b.updated|date:'HH:mm']} | ||
135 | </ngif> | ||
136 | <ngif data-ng-if="b.updated - todaydate < 0"> | ||
137 | {[b.updated|date:'dd/MM/yy HH:mm']} | ||
138 | </ngif> | ||
139 | </div> | ||
140 | <div class="span2"> | ||
141 | <ngif data-ng-if="b.errors.length"> | ||
142 | <span> | ||
143 | <i class="icon-minus-sign red lead"></i> | ||
144 | <a href="{[b.br_page_url]}#errors" class="lead error">{[b.errors.length]} | ||
145 | <ng-pluralize count="b.errors.length" when="{'1':'error','other':'errors'}"></ng-pluralize></a> | ||
146 | </span> | ||
147 | </ngif> | ||
148 | </div> | ||
149 | <div class="span2"> | ||
150 | <!-- we don't have warnings in this case --> | ||
151 | </div> | ||
152 | <div> <span class="lead">Build time: {[b.command_time|timediff]}</span> | ||
153 | <button class="btn pull-right" data-ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.status]" | ||
154 | data-ng-click="buildExistingTarget(b.targets)">Run again</button> | ||
155 | |||
156 | </div> | ||
157 | </case> | ||
158 | |||
159 | <case data-ng-switch-when="queued"> | ||
160 | <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span> </div> | ||
161 | <div class="span4 lead" >Build queued | ||
162 | <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> | ||
163 | </div> | ||
164 | <button class="btn pull-right btn-info" data-ng-click="buildCancel(b)">Cancel</button> | ||
165 | </case> | ||
166 | |||
167 | <case data-ng-switch-when="In Progress"> | ||
168 | <switch data-ng-switch="b.build.length"> | ||
169 | <case data-ng-switch-when="0"> | ||
170 | <div class="lead span5"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span> </div> | ||
171 | <div class="span4 lead"> | ||
172 | Checking out layers | ||
173 | </div> | ||
174 | </case> | ||
175 | <case data-ng-switch-default=""> | ||
176 | <div class="lead span3"> <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span> </div> | ||
177 | <div class="span4 offset1" > | ||
178 | <div class="progress" style="margin-top:5px;" data-toggle="tooltip" tooltip="{[b.build[0].completeper]}% of tasks complete"> | ||
179 | <div style="width: {[b.build[0].completeper]}%;" class="bar"></div> | ||
180 | </div> | ||
181 | </div> | ||
182 | <div class="text-right lead">{[b.build[0].completeper]}% tasks completed</div> | ||
183 | </case> | ||
184 | </case> | ||
185 | |||
186 | 72 | ||
187 | <case data-ng-switch-when="Succeeded"> | 73 | <ul class="unstyled configuration-list" id="freq-build-list"> |
188 | <div class="lead span3"> | 74 | </ul> |
189 | <a data-ng-class="{'Succeeded': 'success', 'Failed': 'error'}[b.build[0].status]" href="{[b.build[0].build_page_url]}"> | 75 | <button class="btn btn-primary" id="freq-build-btn" disabled="disabled">Build selected recipes</button> |
190 | <span data-ng-repeat="t in b.targets" data-ng-include src="'target_display'"></span> | 76 | </div> |
191 | </a> | ||
192 | </div> | ||
193 | <div class="span2 lead"> | ||
194 | <ngif data-ng-if="b.build[0].completed_on - todaydate > 0"> | ||
195 | {[b.build[0].completed_on|date:'HH:mm']} | ||
196 | </ngif> | ||
197 | <ngif data-ng-if="b.build[0].completed_on - todaydate < 0"> | ||
198 | {[b.build[0].completed_on|date:'dd/MM/yy HH:mm']} | ||
199 | </ngif> | ||
200 | </div> | ||
201 | <div class="span2"> | ||
202 | <ngif data-ng-if="b.build[0].errors"> | ||
203 | <span> | ||
204 | <i class="icon-minus-sign red lead"></i> | ||
205 | <a href="{[b.build[0].build_page_url]}#errors" class="lead error">{[b.build[0].errors]} | ||
206 | <ng-pluralize count="b.build[0].errors" when="{'1':'error','other':'errors'}"></ng-pluralize></a> | ||
207 | </span> | ||
208 | </ngif> | ||
209 | </div> | ||
210 | <div class="span2"> | ||
211 | <ngif data-ng-if="b.build[0].warnings"> | ||
212 | <span> | ||
213 | <i class="icon-warning-sign yellow lead"></i> | ||
214 | <a href="{[b.build[0].build_page_url]}#warnings" class="lead warning">{[b.build[0].warnings]} | ||
215 | <ng-pluralize count="b.build[0].warnings" when="{'1':'warning','other':'warnings'}"></ng-pluralize></a> | ||
216 | </span> | ||
217 | </ngif> | ||
218 | </div> | ||
219 | <div> <span class="lead">Build time: <a href="{[b.build[0].build_time_page_url]}">{[b.build[0].build_time|timediff]}</a></span> | ||
220 | <button class="btn pull-right" data-ng-class="{'Succeeded': 'btn-success', 'Failed': 'btn-danger'}[b.build[0].status]" | ||
221 | data-ng-click="buildExistingTarget(b.targets)">Run again</button> | ||
222 | 77 | ||
223 | </div> | 78 | <div class="well well-transparent"> |
224 | </case> | 79 | <h3>Project release</h3> |
225 | 80 | ||
81 | <p class="lead"><span id="project-release-title"></span> <i title="" data-original-title="" id="release-change-toggle" class="icon-pencil"></i></p> | ||
226 | 82 | ||
227 | <case data-ng-switch-default=""> | 83 | <form class="form-inline" id="change-release-form" style="display:none;"> |
228 | <div>FIXME!</div> | 84 | <select></select> |
229 | </case> | 85 | <button class="btn" style="margin-left:5px;" id="change-release-btn">Change</button> <a href="#" id="cancel-release-change" class="btn btn-link">Cancel</a> |
230 | </switch> | 86 | </form> |
231 | <div class="lead pull-right"> | ||
232 | </div> | ||
233 | </div> | 87 | </div> |
234 | </div> | 88 | </div> |
235 | 89 | ||
236 | <h2 class="air">Project configuration</h2> | 90 | <div class="span6"> |
91 | <div class="well well-transparent" id="layer-container"> | ||
92 | <h3>Layers <span class="muted counter">(<span id="project-layers-count"></span>)</span> | ||
93 | <i data-original-title="OpenEmbedded organises metadata into modules called 'layers'. Layers allow you to isolate different types of customizations from each other. <a href='http://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#understanding-and-creating-layers' target='_blank'>More on layers</a>" class="icon-question-sign get-help heading-help" title=""></i> | ||
94 | </h3> | ||
237 | 95 | ||
238 | <!-- alerts section 2 --> | 96 | <div class="alert lead" id="no-layers-in-project" style="display:none"> |
239 | <div data-ng-repeat="a in zone2alerts"> | 97 | You need to add some layers. For that you can: |
240 | <div class="alert alert-dismissible lead" role="alert" data-ng-class="a.type"><button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span></button> | 98 | <ul> |
241 | <span data-ng-bind-html="a.text"></span> | 99 | <li><a href="{% url 'projectlayers' project.id %}">View all layers compatible with this project</a></li> |
242 | </div> | 100 | <li><a href="{% url 'importlayer' project.id %}">Import a layer</a></li> |
243 | </div> | 101 | <li><a href="http://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#understanding-and-creating-layers" target="_blank">Read about layers in the documentation</a></li> |
102 | </ul> | ||
103 | <p>Or type a layer name below.</p> | ||
104 | </div> | ||
244 | 105 | ||
245 | <div class="row-fluid"> | 106 | <form style="margin-top:20px"> |
107 | <!--div class="control-group error"--> | ||
246 | 108 | ||
247 | <!-- project layers --> | ||
248 | <div id="layer-container" class="well well-transparent span4"> | ||
249 | <h3> | ||
250 | Layers <span class="muted counter">({[layers.length]})</span> | ||
251 | <i class="icon-question-sign get-help heading-help" title="Bitbake reads metadata files from modules called 'layers'. Layers allow you to isolate different types of customizations from each other. <a href='http://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#understanding-and-creating-layers' target='_blank'>More on layers</a>"></i> | ||
252 | </h3> | ||
253 | <div class="alert" data-ng-if="project.release && !layers.length"> | ||
254 | <b>You need to add some layers </b> | ||
255 | <p> | ||
256 | You can: | ||
257 | <ul> | ||
258 | <li> <a href="{% url 'projectlayers' project.id %}">View all compatible layers available in Toaster</a> | ||
259 | <li> <a href="{% url 'importlayer' project.id %}">Import a layer</a> | ||
260 | <li> <a href="https://www.yoctoproject.org/docs/1.6.1/dev-manual/dev-manual.html#understanding-and-creating-layers" target="_blank">Read about layers in the manual</a> | ||
261 | </ul> | ||
262 | Or type a layer name below. | ||
263 | </p> | ||
264 | </div> | ||
265 | <form data-ng-submit="layerAdd()"> | ||
266 | <div class="input-append"> | 109 | <div class="input-append"> |
267 | <input type="text" style="width: 100%" id="layer" autocomplete="off" placeholder="Type a layer name" data-minLength="1" data-ng-model="layerAddName" data-typeahead="e for e in getLayersAutocompleteSuggestions($viewValue)" data-typeahead-template-url="layers_suggestion_details" data-typeahead-on-select="onLayerSelect($item, $model, $label)" data-typeahead-editable="false" data-ng-class="{ 'has-error': layerAddName.$invalid }" data-ng-disabled="!project.release" /> | 110 | <input id="layer-add-input" autocomplete="off" placeholder="Type a layer name" data-minlength="1" data-autocomplete="off" data-provide="typeahead" data-source="" type="text"> |
268 | <input type="submit" id="add-layer" class="btn" value="Add" data-ng-disabled="!layerAddName.length"/> | 111 | <button id="add-layer-btn" class="btn" disabled>Add</button> |
269 | </div> | 112 | </div> |
270 | {% csrf_token %} | ||
271 | </form> | ||
272 | <p> | ||
273 | <a href="{% url 'projectlayers' project.id %}">View all compatible layers</a> | ||
274 | <i class="icon-question-sign get-help" title="View all the layers you can build with the release selected for this project, which is {[project.release.desc]}"></i> | ||
275 | | | ||
276 | <a href="{% url 'importlayer' project.id %}">Import layer</a></p> | ||
277 | <ul class="unstyled configuration-list"> | ||
278 | <li data-ng-repeat="l in layers track by l.id" class="animate-repeat"> | ||
279 | <a href="{[l.layerdetailurl]}" class="layer-info" data-toggle="tooltip" tooltip-placement="right" tooltip="{[l.giturl]} | {[l.branch.name]}">{[l.name]}</a> | ||
280 | <i class="icon-trash" data-ng-click="layerDel(l.id)" tooltip="Delete"></i> | ||
281 | </li> | ||
282 | </ul> | ||
283 | </div> | ||
284 | 113 | ||
285 | 114 | <div id="import-alert" class="alert alert-info" style="display:none;"> | |
286 | <!-- project targets --> | 115 | Toaster does not know about this layer. Please <a href="#">import it</a> |
287 | <div id="target-container" class="well well-transparent span4"> | ||
288 | <h3> | ||
289 | Recipes | ||
290 | <i class="icon-question-sign get-help heading-help" title="What you build, often an image recipe that produces a root file system file. Something like <code>core-image-minimal</code> or <code>core-image-sato</code>"></i> | ||
291 | </h3> | ||
292 | <form data-ng-submit="buildNamedTarget()"> | ||
293 | <div class="input-append"> | ||
294 | <input type="text" style="width: 100%" placeholder="Type the recipe(s) you want to build" autocomplete="off" data-minLength="1" data-ng-model="targetName1" data-typeahead="a.name for a in getRecipesAutocompleteSuggestions($viewValue)" data-typeahead-template-url="recipes_suggestion_details" data-ng-disabled="!project.release || !layers.length"> | ||
295 | <button type="submit" class="btn btn-primary" data-ng-disabled="!targetName1.length"> | ||
296 | Build </button> | ||
297 | </div> | ||
298 | {% csrf_token %} | ||
299 | </form> | ||
300 | <p> | ||
301 | <a href="{% url 'projecttargets' project.id %}">View all compatible recipes</a> | ||
302 | <i class="icon-question-sign get-help" title="View all the recipes you can build with the release selected for this project, which is {[project.release.desc]}"></i> | ||
303 | </p> | ||
304 | <div data-ng-if="frequenttargets.length"> | ||
305 | <h4 class="air"> | ||
306 | Most built recipes | ||
307 | </h4> | ||
308 | <ul class="unstyled configuration-list {[mutedtargets]}"> | ||
309 | <li data-ng-repeat="t in frequenttargets"> | ||
310 | <label class="checkbox"> | ||
311 | <input type="checkbox" data-ng-model="mostBuiltTargets[t]" data-ng-disabled="disableBuildCheckbox(t)" data-ng-checked="mostBuiltTargets[t] && !disableBuildCheckbox(t)">{[t]} | ||
312 | </label> | ||
313 | </li> | ||
314 | </ul> | ||
315 | <button class="btn btn-large btn-primary" data-ng-disabled="enableBuildSelectedTargets()" data-ng-click="buildSelectedTargets()">Build selected recipes</button> | ||
316 | </div> | 116 | </div> |
317 | </div> | ||
318 | 117 | ||
319 | <!-- project configuration --> | ||
320 | <div id="machine-distro" class="well well-transparent span4"> | ||
321 | <h3> | ||
322 | Machine | ||
323 | <i class="icon-question-sign get-help heading-help" title="The machine is the hardware for which you want to build. You can only set one machine per project"></i> | ||
324 | </h3> | ||
325 | <p class="lead" id="select-machine-opposite"> | ||
326 | <span>{[machine.name]}</span> | ||
327 | <i id="change-machine" class="icon-pencil" data-ng-click="toggle('#select-machine')"></i> | ||
328 | </p> | ||
329 | <div id="select-machine" style="display: none"> | ||
330 | <div class="alert alert-info"> | ||
331 | <strong>Machine changes have a big impact on build outcome.</strong> | ||
332 | You cannot really compare the builds for the new machine with the previous ones. | ||
333 | </div> | ||
334 | <form data-ng-submit="editProjectSettings('#select-machine')" class="input-append"> | ||
335 | <input type="text" id="machine" autocomplete="off" data-ng-model="machineName" value="{[machine.name]}" data-typeahead="m.name for m in getMachinesAutocompleteSuggestions($viewValue)" data-typeahead-template-url="machines_suggestion_details" /> | ||
336 | <input type="submit" id="apply-change-machine" class="btn" data-ng-disabled="machineName == machine.name || machineName.length == 0" value="Save"/> | ||
337 | <input type="reset" id="cancel-machine" class="btn btn-link" data-ng-click="toggle('#select-machine')" value="Cancel"/> | ||
338 | {% csrf_token %} | ||
339 | </form> | ||
340 | <p> | 118 | <p> |
341 | <a href="{% url 'projectmachines' project.id %}" class="link">View all compatible machines</a> | 119 | <a href="{% url 'projectlayers' project.id %}" id="view-compatible-layers">View compatible layers</a> |
342 | <i class="icon-question-sign get-help" title="View all the machines you can set with the release selected for this project, which is {[project.release.desc]}"></i> | 120 | <i data-original-title="View all the layers you can build with the release selected for this project, which is Yocto Project master" class="icon-question-sign get-help" title=""></i> |
343 | </p> | 121 | | <a href="{% url 'importlayer' project.id %}">Import layer</a> |
344 | </div> | 122 | </p> |
345 | <p class="link-action"> | ||
346 | <a href="{% url 'projectconf' project.id %}" class="link">Edit configuration variables</a> | ||
347 | <i data-original-title="You can set other project configuration options here. Each option, like everything else in the build system, is a variable - value pair" class="icon-question-sign get-help heading-help" title=""></i> | ||
348 | </p> | ||
349 | </div> | ||
350 | </div> | ||
351 | |||
352 | |||
353 | <h2>Project details</h2> | ||
354 | |||
355 | <!-- alerts section 3 --> | ||
356 | <div data-ng-repeat="a in zone3alerts"> | ||
357 | <div class="alert alert-dismissible lead" role="alert" data-ng-class="a.type"><button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span></button> | ||
358 | <span data-ng-bind-html="a.text"></span> | ||
359 | </div> | ||
360 | </div> | ||
361 | |||
362 | |||
363 | <div id="project-details" class="well well-transparent"> | ||
364 | <h3>Project name</h3> | ||
365 | <p class="lead" id="change-project-name-opposite"> | ||
366 | <span >{[project.name]}</span> | ||
367 | <i class="icon-pencil" data-ng-click="toggle('#change-project-name')" ></i> | ||
368 | </p> | ||
369 | <div id="change-project-name" style="display:none;"> | ||
370 | <form data-ng-submit="editProjectSettings('#change-project-name')" class="input-append"> | ||
371 | <input type="text" class="input-xlarge" id="type-project-name" data-ng-model="projectName" value="{[project.name]}"> | ||
372 | <input type="submit" class="btn" value="Save" data-ng-disabled="project.name == projectName"/> | ||
373 | <input type="reset" class="btn btn-link" value="Cancel" data-ng-click="toggle('#change-project-name')"> | ||
374 | </form> | ||
375 | </div> | ||
376 | |||
377 | <h3 data-ng-if="releases.length > 1"> | ||
378 | Release | ||
379 | <i class="icon-question-sign get-help heading-help" title="The version of the build system you want to use"></i> | ||
380 | </h3> | ||
381 | <p data-ng-if="releases.length > 1" class="lead" id="change-project-version-opposite"> | ||
382 | <span id="project-version">{[project.release.desc]}</span> | ||
383 | <i id="change-version" class="icon-pencil" data-ng-click="toggle('#change-project-version')" ></i> | ||
384 | </p> | ||
385 | <div class="div-inline" id="change-project-version" style="display:none;"> | ||
386 | <form data-ng-submit="testProjectSettingsChange('#change-project-version')" class="input-append"> | ||
387 | <select id="select-version" data-ng-model="projectVersion"> | ||
388 | <option data-ng-repeat="r in releases" value="{[r.id]}" data-ng-selected="r.id == project.release.id">{[r.description]}</option> | ||
389 | </select> | ||
390 | <input type="submit" class="btn" style="margin-left:5px;" value="Save" data-ng-disabled="project.release.id == projectVersion"/> | ||
391 | <input type="reset" class="btn btn-link" value="Cancel" data-ng-click="toggle('#change-project-version')"/> | ||
392 | |||
393 | </form> | 123 | </form> |
124 | |||
125 | <ul class="unstyled configuration-list" id="layers-in-project-list"> | ||
126 | </ul> | ||
394 | </div> | 127 | </div> |
395 | </div> | 128 | </div> |
396 | 129 | </div> | |
397 | </div> <!-- end main --> | ||
398 | |||
399 | </div> <!-- end row --> | ||
400 | |||
401 | |||
402 | |||
403 | <!-- load application logic !--> | ||
404 | <script src="{% static "js/projectapp.js" %}"></script> | ||
405 | |||
406 | <!-- dump initial data for use in the angular app --> | ||
407 | <script> | ||
408 | angular.element(document).ready(function() { | ||
409 | scope = angular.element("#main").scope(); | ||
410 | scope.urls = {}; | ||
411 | scope.urls.xhr_build = "{% url 'projectbuilds' project.id %}"; | ||
412 | scope.urls.xhr_edit = "{% url 'project' project.id %}?format=json"; | ||
413 | scope.urls.layers = "{% url 'projectlayers' project.id %}"; | ||
414 | scope.urls.targets = "{% url 'projectavailabletargets' project.id %}"; | ||
415 | scope.urls.machines = "{% url 'projectmachines' project.id %}"; | ||
416 | scope.urls.importlayer = "{% url 'importlayer' project.id %}"; | ||
417 | scope.urls.xhr_datatypeahead = {% url 'xhr_datatypeahead' project.id as xhrdta %}{{xhrdta|json}}; | ||
418 | scope.project = {{prj|json}}; | ||
419 | scope.builds = {{builds|json}}; | ||
420 | scope.layers = {{layers|json}}; | ||
421 | scope.targets = {{targets|json}}; | ||
422 | scope.frequenttargets = {{freqtargets|json}}; | ||
423 | scope.machine = {{machine|json}}; | ||
424 | scope.releases = {{releases|json}}; | ||
425 | scope.layerCount = scope.layers.length; | ||
426 | scope.mutedtargets = (scope.layerCount == 0 ? "muted" : "") | ||
427 | var now = (new Date()).getTime(); | ||
428 | scope.todaydate = now - (now % 86400000); | ||
429 | |||
430 | scope.zone1alerts = []; | ||
431 | scope.zone2alerts = []; | ||
432 | scope.zone3alerts = []; | ||
433 | |||
434 | scope.mostBuiltTargets = {}; | ||
435 | |||
436 | scope.updateDisplayWithCommands(); | ||
437 | scope.validateData(); | ||
438 | |||
439 | scope.init(); | ||
440 | scope.$digest(); | ||
441 | |||
442 | }); | ||
443 | </script> | ||
444 | |||
445 | {% endif %} {# from lvs_nos check #} | ||
446 | {% endblock %} | 130 | {% endblock %} |
diff --git a/bitbake/lib/toaster/toastergui/templates/projecttopbar.html b/bitbake/lib/toaster/toastergui/templates/projecttopbar.html index 46473cb76b..d4d1951ae4 100644 --- a/bitbake/lib/toaster/toastergui/templates/projecttopbar.html +++ b/bitbake/lib/toaster/toastergui/templates/projecttopbar.html | |||
@@ -1,3 +1,8 @@ | |||
1 | <div class="alert alert-success lead" id="project-created-notification" style="margin-top:15px; display:none"> | ||
2 | <button type="button" class="close" data-dismiss="alert">×</button> | ||
3 | Your project <strong>{{project.name}}</strong> has been created. You can now <a href="{% url 'projectmachines' project.id %}">select your target machine</a> and <a href="{% url 'projecttargets' project.id %}">choose image recipes</a> to build. | ||
4 | </div> | ||
5 | |||
1 | <!-- project name --> | 6 | <!-- project name --> |
2 | <div class="row-fluid page-header"> | 7 | <div class="row-fluid page-header"> |
3 | <h1>{{project.name}}</h1> | 8 | <h1>{{project.name}}</h1> |
@@ -7,7 +12,7 @@ | |||
7 | <ul class="nav nav-pills"> | 12 | <ul class="nav nav-pills"> |
8 | <li> | 13 | <li> |
9 | <a href="{% url 'projectbuilds' project.id %}"> | 14 | <a href="{% url 'projectbuilds' project.id %}"> |
10 | Builds (<span class="total-builds"></span>) | 15 | Builds (<span class="total-builds">0</span>) |
11 | </a> | 16 | </a> |
12 | </li> | 17 | </li> |
13 | <li id="topbar-configuration-tab"> | 18 | <li id="topbar-configuration-tab"> |
@@ -15,6 +20,11 @@ | |||
15 | Configuration | 20 | Configuration |
16 | </a> | 21 | </a> |
17 | </li> | 22 | </li> |
23 | <li> | ||
24 | <a href="{% url 'importlayer' project.id %}"> | ||
25 | Import layer | ||
26 | </a> | ||
27 | </li> | ||
18 | <!-- Coming soon | 28 | <!-- Coming soon |
19 | <li> | 29 | <li> |
20 | <a href="my-image-recipes.html"> | 30 | <a href="my-image-recipes.html"> |
@@ -23,16 +33,16 @@ | |||
23 | </li> | 33 | </li> |
24 | --> | 34 | --> |
25 | <li class="pull-right"> | 35 | <li class="pull-right"> |
26 | <form class="form-inline" style="margin-bottom: 0"> | ||
27 | 36 | ||
28 | <i class="icon-question-sign get-help heading-help" data-placement="left" title="" data-original-title="Type the name of one or more recipes you want to build, separated by a space. You can also specify a task by appending a semicolon and a task name to the recipe name, like so: <code>busybox:clean</code>"> | 37 | <i class="icon-question-sign get-help heading-help" data-placement="left" title="" data-original-title="Type the name of one or more recipes you want to build, separated by a space. You can also specify a task by appending a semicolon and a task name to the recipe name, like so: <code>busybox:clean</code>"> |
29 | </i> | 38 | </i> |
30 | <div class="input-append"> | 39 | <div class="input-append"> |
31 | <input type="text" class="input-xlarge build-target-input" placeholder="Type the recipe you want to build" autocomplete="off"> | 40 | <form class="form-inline" style="margin-bottom: 0"> |
32 | <button class="btn btn-primary build-button" data-project-id="{{project.id}}" disabled>Build | 41 | <input type="text" class="input-xlarge input-lg build-target-input" placeholder="Type the recipe you want to build" autocomplete="off" disabled> |
33 | </button> | 42 | <button class="btn btn-primary btn-large build-button" data-project-id="{{project.id}}" disabled>Build |
43 | </button> | ||
44 | </form> | ||
34 | </div> | 45 | </div> |
35 | </form> | 46 | </li> |
36 | </li> | 47 | </ul> |
37 | </ul> | ||
38 | </div> | 48 | </div> |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 688a4c276f..b43a01e951 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
@@ -2132,7 +2132,7 @@ if True: | |||
2132 | prj = Project.objects.create_project(name = request.POST['projectname'], release = release) | 2132 | prj = Project.objects.create_project(name = request.POST['projectname'], release = release) |
2133 | prj.user_id = request.user.pk | 2133 | prj.user_id = request.user.pk |
2134 | prj.save() | 2134 | prj.save() |
2135 | return redirect(reverse(project, args=(prj.pk,)) + "#/newproject") | 2135 | return redirect(reverse(project, args=(prj.pk,)) + "?notify=new-project") |
2136 | 2136 | ||
2137 | except (IntegrityError, BadParameterException) as e: | 2137 | except (IntegrityError, BadParameterException) as e: |
2138 | # fill in page with previously submitted values | 2138 | # fill in page with previously submitted values |
@@ -2238,7 +2238,8 @@ if True: | |||
2238 | } | 2238 | } |
2239 | 2239 | ||
2240 | if prj.release is not None: | 2240 | if prj.release is not None: |
2241 | context["prj"]["release"] = { "id": prj.release.pk, "name": prj.release.name, "desc": prj.release.description} | 2241 | context['release'] = { "id": prj.release.pk, "name": prj.release.name, "description": prj.release.description} |
2242 | |||
2242 | 2243 | ||
2243 | try: | 2244 | try: |
2244 | context["machine"] = {"name": prj.projectvariable_set.get(name="MACHINE").value} | 2245 | context["machine"] = {"name": prj.projectvariable_set.get(name="MACHINE").value} |