diff options
author | Michael Wood <michael.g.wood@intel.com> | 2015-07-31 15:09:12 +0300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-08-01 11:26:12 +0100 |
commit | 80c1586bbb7f661f37754de5ba637c8d6e2185de (patch) | |
tree | 56011e83e1f192a68f4e9014ca266dd6cd76c719 | |
parent | 258c929973e233f212938ea69eec8f83f3285854 (diff) | |
download | poky-80c1586bbb7f661f37754de5ba637c8d6e2185de.tar.gz |
bitbake: toastergui: Add new project page and navigation
This brings in the new project page design and improved navigation. As
this also removes the dependency on Angular it also required that the
entry points to the project page such as machine-change notifications
are also updated.
[YOCTO #7329]
(Bitbake rev: 6489e6eb5c3b0d59063b6d60521fc33fe563e707)
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
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} |