diff options
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} |
