diff options
7 files changed, 1038 insertions, 150 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/css/default.css b/bitbake/lib/toaster/toastergui/static/css/default.css index 199c7531dc..a3fa0ddf6a 100644 --- a/bitbake/lib/toaster/toastergui/static/css/default.css +++ b/bitbake/lib/toaster/toastergui/static/css/default.css | |||
| @@ -232,3 +232,4 @@ dd > span { line-height: 20px; } | |||
| 232 | .animate-repeat.ng-enter.ng-enter-active { | 232 | .animate-repeat.ng-enter.ng-enter-active { |
| 233 | opacity:1; | 233 | opacity:1; |
| 234 | } | 234 | } |
| 235 | .tab-pane table { margin-top: 10px; } | ||
diff --git a/bitbake/lib/toaster/toastergui/static/js/layerdetails.js b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js new file mode 100644 index 0000000000..a5a6330630 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js | |||
| @@ -0,0 +1,404 @@ | |||
| 1 | "use strict" | ||
| 2 | |||
| 3 | function layerDetailsPageInit (ctx) { | ||
| 4 | |||
| 5 | var layerDepInput = $("#layer-dep-input"); | ||
| 6 | var layerDepBtn = $("#add-layer-dependency-btn"); | ||
| 7 | var layerDepsList = $("#layer-deps-list"); | ||
| 8 | var currentLayerDepSelection; | ||
| 9 | var addRmLayerBtn = $("#add-remove-layer-btn"); | ||
| 10 | |||
| 11 | /* setup the dependencies typeahead */ | ||
| 12 | libtoaster.makeTypeahead(layerDepInput, ctx.xhrDataTypeaheadUrl, { type : "layers", project_id: ctx.projectId, include_added: "true" }, function(item){ | ||
| 13 | currentLayerDepSelection = item; | ||
| 14 | |||
| 15 | layerDepBtn.removeAttr("disabled"); | ||
| 16 | }); | ||
| 17 | |||
| 18 | function addRemoveDep(depLayerId, add, doneCb) { | ||
| 19 | var data = { layer_version_id : ctx.layerVersion.id }; | ||
| 20 | if (add) | ||
| 21 | data.add_dep = depLayerId; | ||
| 22 | else | ||
| 23 | data.rm_dep = depLayerId; | ||
| 24 | |||
| 25 | $.ajax({ | ||
| 26 | type: "POST", | ||
| 27 | url: ctx.xhrUpdateLayerUrl, | ||
| 28 | data: data, | ||
| 29 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, | ||
| 30 | success: function (data) { | ||
| 31 | if (data.error != "ok") { | ||
| 32 | console.warn(data.error); | ||
| 33 | } else { | ||
| 34 | doneCb(); | ||
| 35 | } | ||
| 36 | }, | ||
| 37 | error: function (data) { | ||
| 38 | console.warn("Call failed"); | ||
| 39 | console.warn(data); | ||
| 40 | } | ||
| 41 | }); | ||
| 42 | } | ||
| 43 | |||
| 44 | function layerRemoveClick() { | ||
| 45 | var toRemove = $(this).parent().data('layer-id'); | ||
| 46 | var layerDepItem = $(this); | ||
| 47 | |||
| 48 | addRemoveDep(toRemove, false, function(){ | ||
| 49 | layerDepItem.parent().fadeOut(function (){ | ||
| 50 | layerDepItem.remove(); | ||
| 51 | }); | ||
| 52 | }); | ||
| 53 | } | ||
| 54 | |||
| 55 | /* Add dependency layer button click handler */ | ||
| 56 | layerDepBtn.click(function(){ | ||
| 57 | if (currentLayerDepSelection == undefined) | ||
| 58 | return; | ||
| 59 | |||
| 60 | addRemoveDep(currentLayerDepSelection.id, true, function(){ | ||
| 61 | /* Make a list item for the new layer dependency */ | ||
| 62 | var newLayerDep = $("<li><a></a><span class=\"icon-trash\" data-toggle=\"tooltip\" title=\"Delete\"></span></li>"); | ||
| 63 | |||
| 64 | newLayerDep.data('layer-id', currentLayerDepSelection.id); | ||
| 65 | newLayerDep.children("span").tooltip(); | ||
| 66 | |||
| 67 | var link = newLayerDep.children("a"); | ||
| 68 | link.attr("href", ctx.layerDetailsUrl+String(currentLayerDepSelection.id)); | ||
| 69 | link.text(currentLayerDepSelection.name); | ||
| 70 | link.tooltip({title: currentLayerDepSelection.tooltip, placement: "right"}); | ||
| 71 | |||
| 72 | /* Connect up the tash icon */ | ||
| 73 | var trashItem = newLayerDep.children("span"); | ||
| 74 | trashItem.click(layerRemoveClick); | ||
| 75 | |||
| 76 | layerDepsList.append(newLayerDep); | ||
| 77 | /* Clear the current selection */ | ||
| 78 | layerDepInput.val(""); | ||
| 79 | currentLayerDepSelection = undefined; | ||
| 80 | layerDepBtn.attr("disabled","disabled"); | ||
| 81 | }); | ||
| 82 | }); | ||
| 83 | |||
| 84 | $(".icon-pencil").click(function (){ | ||
| 85 | var mParent = $(this).parent("dd"); | ||
| 86 | mParent.prev().css("margin-top", "10px"); | ||
| 87 | mParent.children("form").slideDown(); | ||
| 88 | var currentVal = mParent.children(".current-value"); | ||
| 89 | currentVal.hide(); | ||
| 90 | /* Set the current value to the input field */ | ||
| 91 | mParent.find("textarea,input").val(currentVal.text()); | ||
| 92 | /* Hides the "Not set" text */ | ||
| 93 | mParent.children(".muted").hide(); | ||
| 94 | /* We're editing so hide the delete icon */ | ||
| 95 | mParent.children(".delete-current-value").hide(); | ||
| 96 | mParent.find(".cancel").show(); | ||
| 97 | $(this).hide(); | ||
| 98 | }); | ||
| 99 | |||
| 100 | $(".delete-current-value").click(function(){ | ||
| 101 | var mParent = $(this).parent("dd"); | ||
| 102 | mParent.find("input").val(""); | ||
| 103 | mParent.find("textarea").val(""); | ||
| 104 | mParent.find(".change-btn").click(); | ||
| 105 | }); | ||
| 106 | |||
| 107 | $(".cancel").click(function(){ | ||
| 108 | var mParent = $(this).parents("dd"); | ||
| 109 | $(this).hide(); | ||
| 110 | mParent.children("form").slideUp(function(){ | ||
| 111 | mParent.children(".current-value").show(); | ||
| 112 | /* Show the "Not set" text if we ended up with no value */ | ||
| 113 | if (!mParent.children(".current-value").html()){ | ||
| 114 | mParent.children(".muted").fadeIn(); | ||
| 115 | mParent.children(".delete-current-value").hide(); | ||
| 116 | } else { | ||
| 117 | mParent.children(".delete-current-value").show(); | ||
| 118 | } | ||
| 119 | |||
| 120 | mParent.children(".icon-pencil").show(); | ||
| 121 | mParent.prev().css("margin-top", "0px"); | ||
| 122 | }); | ||
| 123 | }); | ||
| 124 | |||
| 125 | $(".build-target-btn").click(function(){ | ||
| 126 | /* fire a build */ | ||
| 127 | var target = $(this).data('target-name'); | ||
| 128 | libtoaster.startABuild(ctx.projectBuildUrl, ctx.projectId, target, null, null); | ||
| 129 | window.location.replace(ctx.projectPageUrl); | ||
| 130 | }); | ||
| 131 | |||
| 132 | $(".select-machine-btn").click(function(){ | ||
| 133 | var data = { machineName : $(this).data('machine-name') }; | ||
| 134 | libtoaster.editProject(ctx.xhrEditProjectUrl, ctx.projectId, data, | ||
| 135 | function (){ | ||
| 136 | window.location.replace(ctx.projectPageUrl); | ||
| 137 | }, null); | ||
| 138 | }); | ||
| 139 | |||
| 140 | function defaultAddBtnText(){ | ||
| 141 | var text = " Add the "+ctx.layerVersion.name+" layer to your project"; | ||
| 142 | addRmLayerBtn.text(text); | ||
| 143 | addRmLayerBtn.prepend("<span class=\"icon-plus\"></span>"); | ||
| 144 | addRmLayerBtn.removeClass("btn-danger"); | ||
| 145 | } | ||
| 146 | |||
| 147 | $("#details-tab").on('show', function(){ | ||
| 148 | if (!ctx.layerVersion.inCurrentPrj) | ||
| 149 | defaultAddBtnText(); | ||
| 150 | |||
| 151 | window.location.hash = "details"; | ||
| 152 | }); | ||
| 153 | |||
| 154 | function targetsTabShow(){ | ||
| 155 | if (!ctx.layerVersion.inCurrentPrj){ | ||
| 156 | if (ctx.numTargets > 0) { | ||
| 157 | var text = " Add the "+ctx.layerVersion.name+" layer to your project "+ | ||
| 158 | "to enable these targets"; | ||
| 159 | addRmLayerBtn.text(text); | ||
| 160 | addRmLayerBtn.prepend("<span class=\"icon-plus\"></span>"); | ||
| 161 | } else { | ||
| 162 | defaultAddBtnText(); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | window.location.hash = "targets"; | ||
| 167 | } | ||
| 168 | |||
| 169 | $("#targets-tab").on('show', targetsTabShow); | ||
| 170 | |||
| 171 | function machinesTabShow(){ | ||
| 172 | if (!ctx.layerVersion.inCurrentPrj) { | ||
| 173 | if (ctx.numMachines > 0){ | ||
| 174 | var text = " Add the "+ctx.layerVersion.name+" layer to your project " + | ||
| 175 | "to enable these machines"; | ||
| 176 | addRmLayerBtn.text(text); | ||
| 177 | addRmLayerBtn.prepend("<span class=\"icon-plus\"></span>"); | ||
| 178 | } else { | ||
| 179 | defaultAddBtnText(); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | window.location.hash = "machines"; | ||
| 184 | } | ||
| 185 | |||
| 186 | $("#machines-tab").on('show', machinesTabShow); | ||
| 187 | |||
| 188 | $(".pagesize").change(function(){ | ||
| 189 | var search = libtoaster.parseUrlParams(); | ||
| 190 | search.limit = this.value; | ||
| 191 | |||
| 192 | window.location.search = libtoaster.dumpsUrlParams(search); | ||
| 193 | }); | ||
| 194 | |||
| 195 | /* Enables the Build target and Select Machine buttons and switches the | ||
| 196 | * add/remove button | ||
| 197 | */ | ||
| 198 | function setLayerInCurrentPrj(added, depsList) { | ||
| 199 | ctx.layerVersion.inCurrentPrj = added; | ||
| 200 | var alertMsg = $("#alert-msg"); | ||
| 201 | /* Reset alert message */ | ||
| 202 | alertMsg.text(""); | ||
| 203 | |||
| 204 | if (added){ | ||
| 205 | /* enable and switch all the button states */ | ||
| 206 | $(".build-target-btn").removeAttr("disabled"); | ||
| 207 | $(".select-machine-btn").removeAttr("disabled"); | ||
| 208 | addRmLayerBtn.addClass("btn-danger"); | ||
| 209 | addRmLayerBtn.data('directive', "remove"); | ||
| 210 | addRmLayerBtn.text(" Delete the "+ctx.layerVersion.name+" layer from your project"); | ||
| 211 | addRmLayerBtn.prepend("<span class=\"icon-trash\"></span>"); | ||
| 212 | |||
| 213 | if (depsList) { | ||
| 214 | alertMsg.append("You have added <strong>"+(depsList.length+1)+"</strong> layers: <span id=\"layer-affected-name\"></span> and its dependencies "); | ||
| 215 | |||
| 216 | /* Build the layer deps list */ | ||
| 217 | depsList.map(function(layer, i){ | ||
| 218 | var link = $("<a></a>"); | ||
| 219 | |||
| 220 | link.attr("href", layer.layerdetailurl); | ||
| 221 | link.text(layer.name); | ||
| 222 | link.tooltip({title: layer.tooltip}); | ||
| 223 | |||
| 224 | if (i != 0) | ||
| 225 | alertMsg.append(", "); | ||
| 226 | |||
| 227 | alertMsg.append(link); | ||
| 228 | }); | ||
| 229 | } else { | ||
| 230 | alertMsg.append("You have added <strong>1</strong> layer: <span id=\"layer-affected-name\"></span>"); | ||
| 231 | } | ||
| 232 | } else { | ||
| 233 | /* disable and switch all the button states */ | ||
| 234 | $(".build-target-btn").attr("disabled","disabled"); | ||
| 235 | $(".select-machine-btn").attr("disabled", "disabled"); | ||
| 236 | addRmLayerBtn.removeClass("btn-danger"); | ||
| 237 | addRmLayerBtn.data('directive', "add"); | ||
| 238 | |||
| 239 | /* "special" handler so that we get the correct button text which depends | ||
| 240 | * on which tab is currently visible. Unfortunately we can't just call | ||
| 241 | * tab('show') as if it's already visible it doesn't run the event. | ||
| 242 | */ | ||
| 243 | switch ($(".nav-pills .active a").prop('id')){ | ||
| 244 | case 'machines-tab': | ||
| 245 | machinesTabShow(); | ||
| 246 | break; | ||
| 247 | case 'targets-tab': | ||
| 248 | targetsTabShow(); | ||
| 249 | break; | ||
| 250 | default: | ||
| 251 | defaultAddBtnText(); | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | |||
| 255 | alertMsg.append("You have deleted <strong>1</strong> layer: <span id=\"layer-affected-name\"></span>"); | ||
| 256 | } | ||
| 257 | |||
| 258 | alertMsg.children("#layer-affected-name").text(ctx.layerVersion.name); | ||
| 259 | $("#alert-area").show(); | ||
| 260 | } | ||
| 261 | |||
| 262 | /* Add or remove this layer from the project */ | ||
| 263 | addRmLayerBtn.click(function() { | ||
| 264 | var directive = $(this).data('directive'); | ||
| 265 | |||
| 266 | if (directive == 'add') { | ||
| 267 | /* If adding get the deps for this layer */ | ||
| 268 | libtoaster.getLayerDepsForProject(ctx.xhrDataTypeaheadUrl, ctx.projectId, ctx.layerVersion.id, function (data) { | ||
| 269 | /* got result for dependencies */ | ||
| 270 | if (data.list.length == 0){ | ||
| 271 | var editData = { layerAdd : ctx.layerVersion.id }; | ||
| 272 | libtoaster.editProject(ctx.xhrEditProjectUrl, ctx.projectId, editData, | ||
| 273 | function() { | ||
| 274 | setLayerInCurrentPrj(true); | ||
| 275 | }); | ||
| 276 | return; | ||
| 277 | } else { | ||
| 278 | /* The add deps will include this layer so no need to add it | ||
| 279 | * separately. | ||
| 280 | */ | ||
| 281 | show_layer_deps_modal(ctx.projectId, ctx.layerVersion, data.list, null, null, true, function () { | ||
| 282 | /* Success add deps and layer */ | ||
| 283 | setLayerInCurrentPrj(true, data.list); | ||
| 284 | }); | ||
| 285 | } | ||
| 286 | }, null); | ||
| 287 | } else if (directive == 'remove') { | ||
| 288 | var editData = { layerDel : ctx.layerVersion.id }; | ||
| 289 | |||
| 290 | libtoaster.editProject(ctx.xhrEditProjectUrl, ctx.projectId, editData, | ||
| 291 | function () { | ||
| 292 | /* Success removed layer */ | ||
| 293 | //window.location.reload(); | ||
| 294 | setLayerInCurrentPrj(false); | ||
| 295 | }, function () { | ||
| 296 | console.warn ("Removing layer from project failed"); | ||
| 297 | }); | ||
| 298 | } | ||
| 299 | }); | ||
| 300 | |||
| 301 | /* Handler for all of the Change buttons */ | ||
| 302 | $(".change-btn").click(function(){ | ||
| 303 | var mParent = $(this).parent(); | ||
| 304 | var prop = $(this).data('layer-prop'); | ||
| 305 | |||
| 306 | /* We have inputs, select and textareas to potentially grab the value | ||
| 307 | * from. | ||
| 308 | */ | ||
| 309 | var entryElement = mParent.find("input"); | ||
| 310 | if (entryElement.length == 0) | ||
| 311 | entryElement = mParent.find("textarea"); | ||
| 312 | if (entryElement.length == 0) | ||
| 313 | entryElement = mParent.find("select"); | ||
| 314 | if (entryElement.length == 0) { | ||
| 315 | console.warn("Could not find element to get data from for this change"); | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | |||
| 319 | var data = { layer_version_id: ctx.layerVersion.id }; | ||
| 320 | data[prop] = entryElement.val(); | ||
| 321 | |||
| 322 | $.ajax({ | ||
| 323 | type: "POST", | ||
| 324 | url: ctx.xhrUpdateLayerUrl, | ||
| 325 | data: data, | ||
| 326 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, | ||
| 327 | success: function (data) { | ||
| 328 | if (data.error != "ok") { | ||
| 329 | console.warn(data.error); | ||
| 330 | } else { | ||
| 331 | /* success layer property changed */ | ||
| 332 | var inputArea = mParent.parents("dd"); | ||
| 333 | var text; | ||
| 334 | /* We don't actually want the value from the select option we want | ||
| 335 | * the text that represents the value to display | ||
| 336 | */ | ||
| 337 | text = entryElement.children("option:selected").text(); | ||
| 338 | if (!text) | ||
| 339 | text = entryElement.val(); | ||
| 340 | |||
| 341 | /* Hide the "Not set" text if it's visible */ | ||
| 342 | inputArea.find(".muted").hide(); | ||
| 343 | inputArea.find(".current-value").text(text); | ||
| 344 | /* Same behaviour as cancel in that we hide the form/show current | ||
| 345 | * value. | ||
| 346 | */ | ||
| 347 | inputArea.find(".cancel").click(); | ||
| 348 | } | ||
| 349 | }, | ||
| 350 | error: function (data) { | ||
| 351 | console.warn("Call failed"); | ||
| 352 | console.warn(data); | ||
| 353 | } | ||
| 354 | }); | ||
| 355 | }); | ||
| 356 | |||
| 357 | /* Disable the change button when we have no data in the input */ | ||
| 358 | $("dl input, dl textarea").keyup(function() { | ||
| 359 | if ($(this).val().length == 0) | ||
| 360 | $(this).parent().children(".change-btn").attr("disabled", "disabled"); | ||
| 361 | else | ||
| 362 | $(this).parent().children(".change-btn").removeAttr("disabled"); | ||
| 363 | }); | ||
| 364 | |||
| 365 | /* This checks to see if the dt's dd has data in it or if the change data | ||
| 366 | * form is visible, otherwise hide it | ||
| 367 | */ | ||
| 368 | $("dl").children().each(function (){ | ||
| 369 | if ($(this).is("dt")) { | ||
| 370 | var dd = $(this).next("dd"); | ||
| 371 | if (!dd.children("form:visible")|| !dd.find(".current-value").html()){ | ||
| 372 | if (ctx.layerVersion.sourceId == 3){ | ||
| 373 | /* There's no current value and the layer is editable | ||
| 374 | * so show the "Not set" and hide the delete icon | ||
| 375 | */ | ||
| 376 | dd.find(".muted").show(); | ||
| 377 | dd.find(".delete-current-value").hide(); | ||
| 378 | } else { | ||
| 379 | /* We're not viewing an editable layer so hide the empty dd/dl pair */ | ||
| 380 | $(this).hide(); | ||
| 381 | dd.hide(); | ||
| 382 | } | ||
| 383 | } | ||
| 384 | } | ||
| 385 | }); | ||
| 386 | |||
| 387 | /* Clear the current search selection and reload the results */ | ||
| 388 | $("#target-search-clear").click(function(){ | ||
| 389 | $("#target-search").val(""); | ||
| 390 | $(this).parents("form").submit(); | ||
| 391 | }); | ||
| 392 | |||
| 393 | $("#machine-search-clear").click(function(){ | ||
| 394 | $("#machine-search").val(""); | ||
| 395 | $(this).parents("form").submit(); | ||
| 396 | }); | ||
| 397 | |||
| 398 | |||
| 399 | layerDepsList.find(".icon-trash").click(layerRemoveClick); | ||
| 400 | layerDepsList.find("a").tooltip(); | ||
| 401 | $(".icon-trash").tooltip(); | ||
| 402 | $(".commit").tooltip(); | ||
| 403 | |||
| 404 | } | ||
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js index a2a0abd45b..04264cd8ba 100644 --- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js +++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js | |||
| @@ -161,6 +161,39 @@ var libtoaster = (function (){ | |||
| 161 | }); | 161 | }); |
| 162 | }; | 162 | }; |
| 163 | 163 | ||
| 164 | /* parses the query string of the current window.location to an object */ | ||
| 165 | function _parseUrlParams() { | ||
| 166 | string = window.location.search | ||
| 167 | string = string.substr(1); | ||
| 168 | stringArray = string.split ("&"); | ||
| 169 | obj = {}; | ||
| 170 | |||
| 171 | for (i in stringArray) { | ||
| 172 | keyVal = stringArray[i].split ("="); | ||
| 173 | obj[keyVal[0]] = keyVal[1]; | ||
| 174 | } | ||
| 175 | |||
| 176 | return obj; | ||
| 177 | }; | ||
| 178 | |||
| 179 | /* takes a flat object and outputs it as a query string | ||
| 180 | * e.g. the output of dumpsUrlParams | ||
| 181 | */ | ||
| 182 | function _dumpsUrlParams(obj) { | ||
| 183 | var str = "?"; | ||
| 184 | |||
| 185 | for (key in obj){ | ||
| 186 | if (!obj[key]) | ||
| 187 | continue; | ||
| 188 | |||
| 189 | str += key+ "="+obj[key].toString(); | ||
| 190 | str += "&"; | ||
| 191 | } | ||
| 192 | |||
| 193 | return str; | ||
| 194 | }; | ||
| 195 | |||
| 196 | |||
| 164 | return { | 197 | return { |
| 165 | reload_params : reload_params, | 198 | reload_params : reload_params, |
| 166 | startABuild : _startABuild, | 199 | startABuild : _startABuild, |
| @@ -169,6 +202,8 @@ var libtoaster = (function (){ | |||
| 169 | getLayerDepsForProject : _getLayerDepsForProject, | 202 | getLayerDepsForProject : _getLayerDepsForProject, |
| 170 | editProject : _editProject, | 203 | editProject : _editProject, |
| 171 | debug: false, | 204 | debug: false, |
| 205 | parseUrlParams : _parseUrlParams, | ||
| 206 | dumpsUrlParams : _dumpsUrlParams, | ||
| 172 | } | 207 | } |
| 173 | })(); | 208 | })(); |
| 174 | 209 | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/layerdetails.html b/bitbake/lib/toaster/toastergui/templates/layerdetails.html index 78dc54bfd1..c69f9e945a 100644 --- a/bitbake/lib/toaster/toastergui/templates/layerdetails.html +++ b/bitbake/lib/toaster/toastergui/templates/layerdetails.html | |||
| @@ -1,159 +1,505 @@ | |||
| 1 | {% extends "baseprojectpage.html" %} | 1 | {% extends "baseprojectpage.html" %} |
| 2 | {% load projecttags %} | 2 | {% load projecttags %} |
| 3 | {% load humanize %} | 3 | {% load humanize %} |
| 4 | 4 | {% load static %} | |
| 5 | {% block localbreadcrumb %} | 5 | {% block localbreadcrumb %} |
| 6 | <li>Layer Details</li> | 6 | <li><a href="{% url 'layers' %}">All Layers</a></li> |
| 7 | <li> | ||
| 8 | {{layerversion.layer.name}} ({{layerversion.commit|truncatechars:13}}) | ||
| 9 | </li> | ||
| 7 | {% endblock %} | 10 | {% endblock %} |
| 8 | |||
| 9 | {% block projectinfomain %} | 11 | {% block projectinfomain %} |
| 10 | <div class="page-header"> | 12 | |
| 11 | <h1>Layer Details</h1> | 13 | |
| 12 | </div> | 14 | <script src="{% static 'js/layerdetails.js' %}"></script> |
| 13 | 15 | <script> | |
| 14 | <div class="row-fluid span7 tabbable"> | 16 | |
| 15 | <ul class="nav nav-pills"> | 17 | $(document).ready(function (){ |
| 16 | <li class="active"> | 18 | var ctx = { |
| 17 | <a data-toggle="tab" href="#information">Layer details</a> | 19 | projectBuildUrl : "{% url 'xhr_build' %}", |
| 18 | </li> | 20 | layerDetailsUrl : "{% url 'layerdetails' %}", |
| 19 | <li> | 21 | projectPageUrl : "{% url 'project' project.id %}", |
| 20 | <a data-toggle="tab" href="#targets">Targets (0)</a> | 22 | xhrEditProjectUrl : "{% url 'xhr_projectedit' project.id %}", |
| 21 | </li> | 23 | xhrDataTypeaheadUrl : "{% url 'xhr_datatypeahead' %}", |
| 22 | <li> | 24 | xhrUpdateLayerUrl : "{% url 'xhr_updatelayer' %}", |
| 23 | <a data-toggle="tab" href="#machines">Machines (0)</a> | 25 | projectId : {{project.id}}, |
| 24 | </li> | 26 | numTargets : {{total_targets}}, |
| 25 | <li> | 27 | numMachines: {{machines|length}}, |
| 26 | <a data-toggle="tab" href="#classes">Classes (0)</a> | 28 | layerVersion : { |
| 27 | </li> | 29 | name : "{{layerversion.layer.name}}", |
| 28 | <li> | 30 | id : {{layerversion.id}}, |
| 29 | <a data-toggle="tab" href="#bbappends">bbappends (0)</a> | 31 | commit: "{{layerversion.commit}}", |
| 30 | </li> | 32 | inCurrentPrj : {{layer_in_project}}, |
| 31 | </ul> | 33 | url : "{% url 'layerdetails' layerversion.id %}", |
| 32 | <div class="tab-content"> | 34 | sourceId: {{layerversion.layer_source_id}}, |
| 33 | <div name="information" id="information" class="tab-pane active"> | 35 | } |
| 34 | <dl class="dl-horizontal"> | 36 | }; |
| 35 | <dt class=""> | 37 | |
| 36 | <i class="icon-question-sign get-help" title="Fetch/clone URL of the repository"></i> | 38 | try { |
| 37 | Repository URL | 39 | layerDetailsPageInit(ctx); |
| 38 | </dt> | 40 | } catch (e) { |
| 39 | <dd> | 41 | document.write("Sorry, An error has occurred loading this page"); |
| 40 | <form id="change-repo-form" class="control-group"> | 42 | console.warn(e); |
| 41 | <div class="input-append"> | 43 | } |
| 42 | <input type="text" class="input-xlarge" id="type-repo" value="{{layerversion.layer.vcs_url}}"> | 44 | }); |
| 43 | <button id="apply-change-repo" class="btn" type="button">Change</button> | 45 | </script> |
| 44 | <!--a href="#" id="cancel-change-repo" class="btn btn-link">Cancel</a--> | 46 | |
| 45 | </div> | 47 | {# If this is not an imported layer then hide the edit ui #} |
| 46 | <span class="help-block">Cloning this Git repository failed</span> | 48 | {% if layerversion.layer_source_id != 3 %} |
| 47 | </form> | 49 | <style> |
| 48 | </dd> | 50 | .icon-pencil { |
| 49 | <dt> | 51 | display:none; |
| 50 | <i class="icon-question-sign get-help" title="Subdirectory within the repository where the layer is located, if not in the root (usually only used if the repository contains more than one layer)"></i> | 52 | } |
| 51 | Repository subdirectory | 53 | .delete-current-value{ |
| 52 | </dt> | 54 | display: none; |
| 53 | <dd> | 55 | } |
| 54 | <span id="subdir">{{layerversion.dirpath}}</span> | 56 | li .icon-trash { |
| 55 | <i id="change-subdir" class="icon-pencil"></i> | 57 | display:none; |
| 56 | <i id="delete-subdir" class="icon-trash"></i> | 58 | } |
| 57 | <form id="change-subdir-form" style="display:none;"> | 59 | .add-deps { |
| 58 | <div class="input-append"> | 60 | display:none; |
| 59 | <input type="text" id="type-subdir" value="meta-acer"> | 61 | } |
| 60 | <button id="apply-change-subdir" class="btn" type="button">Change</button> | 62 | </style> |
| 61 | <a href="#" id="cancel-change-subdir" class="btn btn-link">Cancel</a> | 63 | {% endif %} |
| 62 | </div> | 64 | |
| 63 | </form> | 65 | {% include "layers_dep_modal.html" %} |
| 64 | </dd> | 66 | <div class="container-fluid top-padded"> |
| 65 | <dt>Brach, tag or commit</dt> | 67 | <div class="row-fluid"> |
| 66 | <dd> | 68 | <div class="span11"> |
| 67 | {{layerversion.up_branch.name}} | 69 | <div class="page-header"> |
| 68 | <i class="icon-pencil"></i> | 70 | <h1>{{layerversion.layer.name}} <small class="commit" data-toggle="tooltip" title="{{layerversion.commit}}">({{layerversion.commit|truncatechars:13}})</small></h1> |
| 69 | </dd> | 71 | </div> |
| 70 | <dt> | ||
| 71 | <i class="icon-question-sign get-help" title="The Yocto Project versions with which this layer is compatible. Currently Toaster supports Yocto Project 1.6 and 1.7"></i> | ||
| 72 | Yocto Project compatibility | ||
| 73 | </dt> | ||
| 74 | <dd> | ||
| 75 | <i class="icon-pencil"></i> | ||
| 76 | </dd> | ||
| 77 | <dt> | ||
| 78 | <i class="icon-question-sign get-help" title="Other layers this layer depends upon"></i> | ||
| 79 | Layer dependencies | ||
| 80 | </dt> | ||
| 81 | <dd> | ||
| 82 | <ul class="unstyled"> | ||
| 83 | {% for ld in layer.dependencies.all %} | ||
| 84 | <li> | ||
| 85 | <a href="#">openembedded core (meta)</a> | ||
| 86 | <i class="icon-trash"></i> | ||
| 87 | </li> | ||
| 88 | {% endfor %} | ||
| 89 | </ul> | ||
| 90 | <div class="input-append"> | ||
| 91 | <input type="text" autocomplete="off" data-minLength="1" data-autocomplete="off" | ||
| 92 | data-provide="typeahead" data-source=' | ||
| 93 | ' | ||
| 94 | placeholder="Type a layer name" id="layer-dependency"> | ||
| 95 | <a class="btn" type="button" id="add-layer-dependency" disabled> | ||
| 96 | Add layer | ||
| 97 | </a> | ||
| 98 | </div> | ||
| 99 | <span class="help-block">You can only add layers Toaster knows about</span> | ||
| 100 | </dd> | ||
| 101 | </dl> | ||
| 102 | </div> | ||
| 103 | <div name="targets" id="targets" class="tab-pane"> | ||
| 104 | <div class="alert alert-info"> | ||
| 105 | <strong>There is no target data for {{layerversion.layer.name}} ... yet</strong> <br /> | ||
| 106 | Toaster learns about layers as they are built. Once you have used {{layerversion.layer.name}} in a build, Toaster will show you | ||
| 107 | here the targets it provides. | ||
| 108 | </div> | ||
| 109 | </div> | ||
| 110 | <div name="machines" id="machines" class="tab-pane"> | ||
| 111 | <div class="alert alert-info"> | ||
| 112 | <strong>There is no machine data for {{layerversion.layer.name}} ... yet</strong> <br /> | ||
| 113 | Toaster learns about layers as they are built. Once you have used {{layerversion.layer.name}} in a build, Toaster will show you | ||
| 114 | here the machines it provides. | ||
| 115 | </div> | ||
| 116 | </div> | ||
| 117 | </div> | 72 | </div> |
| 118 | </div> | 73 | </div> |
| 119 | <div class="row span4 well"> | 74 | |
| 120 | <h2>About {{layerversion.layer.name}}</h2> | 75 | <div class="row-fluid"> |
| 121 | <dl> | 76 | <div class="span7"> |
| 122 | 77 | <div class="tabbable"> | |
| 123 | <dt> | 78 | <div class="alert alert-info lead" id="alert-area" style="display:none"> |
| 124 | Summary | 79 | <button type="button" class="close" id="dismiss-alert" data-dismiss="alert">×</button> |
| 125 | <i class="icon-question-sign get-help" title="One-line description of the layer"></i> | 80 | <span id="alert-msg"></span> |
| 126 | </dt> | 81 | <p style="margin-top:10px;"><a href="{% url 'project' project.id %}">Go to project configuration</a></p> |
| 127 | <dd> | 82 | </div> |
| 128 | <span >{{layerversion.layer.summary}}</span> | 83 | <ul class="nav nav-pills"> |
| 129 | <i class="icon-pencil"></i> | 84 | <li class="active"> |
| 130 | </dd> | 85 | <a data-toggle="tab" href="#information" id="details-tab">Layer details</a> |
| 131 | <!--form> | 86 | </li> |
| 132 | <textarea class="span12" rows="2"></textarea> | 87 | <li> |
| 133 | <button class="btn" type="button">Change</button> | 88 | <a data-toggle="tab" href="#targets" id="targets-tab">Targets ({{total_targets}})</a> |
| 134 | <a href="#" class="btn btn-link">Cancel</a> | 89 | </li> |
| 135 | </form--> | 90 | <li> |
| 136 | <dt> | 91 | <a data-toggle="tab" href="#machines" id="machines-tab">Machines ({{total_machines}})</a> |
| 137 | Description | 92 | </li> |
| 138 | </dt> | 93 | </ul> |
| 139 | <dd> | 94 | </div> |
| 140 | <span >{{layerversion.layer.description}}</span> | 95 | <div class="tab-content"> |
| 141 | <i class="icon-pencil"></i> | 96 | <span class="button-place"> |
| 142 | </dd> | 97 | {% if layer_in_project == 0 %} |
| 143 | <!--form> | 98 | <button id="add-remove-layer-btn" data-directive="add" class="btn btn-large btn-block"> |
| 144 | <textarea class="span12" rows="6"></textarea> | 99 | <span class="icon-plus"></span> |
| 145 | <button class="btn" type="button">Change</button> | 100 | Add the {{layerversion.layer.name}} layer to your project |
| 146 | <a href="#" class="btn btn-link">Cancel</a> | 101 | </button> |
| 147 | </form--> | 102 | {% else %} |
| 148 | <dt> | 103 | <button id="add-remove-layer-btn" data-directive="remove" class="btn btn-block btn-large btn-danger"> |
| 149 | Maintainer(s) | 104 | <span class="icon-trash"></span> |
| 150 | </dt> | 105 | Delete the {{layerversion.layer.name}} layer from your project |
| 151 | <dd> | 106 | </button> |
| 152 | <span class="muted">Not set</span> | 107 | {% endif %} |
| 153 | <i class="icon-pencil"></i> | 108 | </span> |
| 154 | </dd> | 109 | |
| 155 | </dl> | 110 | <!-- layer details pane --> |
| 156 | </div> | 111 | <div name="information" id="information" class="tab-pane active"> |
| 112 | <dl class="dl-horizontal"> | ||
| 113 | <dt class=""> | ||
| 114 | <i class="icon-question-sign get-help" title="Fetch/clone URL of the repository"></i> | ||
| 115 | Repository URL | ||
| 116 | </dt> | ||
| 117 | <dd> | ||
| 118 | <span class="current-value">{{layerversion.layer.vcs_url}}</span> | ||
| 119 | {% if layerversion.get_vcs_link_url %} | ||
| 120 | <a href="{{layerversion.get_vcs_link_url}}/" class="icon-share get-info"></a> | ||
| 121 | {% endif %} | ||
| 122 | <form id="change-repo-form" class="control-group" style="display:none"> | ||
| 123 | <div class="input-append"> | ||
| 124 | <input type="text" class="input-xlarge" value="{{layerversion.layer.vcs_url}}"> | ||
| 125 | <button data-layer-prop="vcs_url" class="btn change-btn" type="button">Save</button> | ||
| 126 | <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a> | ||
| 127 | </div> | ||
| 128 | </form> | ||
| 129 | <i class="icon-pencil" ></i> | ||
| 130 | </dd> | ||
| 131 | <dt> | ||
| 132 | <i class="icon-question-sign get-help" title="Subdirectory within the repository where the layer is located, if not in the root (usually only used if the repository contains more than one layer)"></i> | ||
| 133 | Repository subdirectory | ||
| 134 | </dt> | ||
| 135 | <dd> | ||
| 136 | <span class="muted" style="display:none">Not set</span> | ||
| 137 | <span class="current-value">{{layerversion.dirpath}}</span> | ||
| 138 | {% if layerversion.get_vcs_dirpath_link_url %} | ||
| 139 | <a href="{{layerversion.get_vcs_dirpath_link_url}}" class="icon-share get-info"></a> | ||
| 140 | {% endif %} | ||
| 141 | <form id="change-subdir-form" style="display:none;"> | ||
| 142 | <div class="input-append"> | ||
| 143 | <input type="text" value="{{layerversion.dirpath}}"> | ||
| 144 | <button data-layer-prop="dirpath" class="btn change-btn" type="button">Save</button> | ||
| 145 | <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a> | ||
| 146 | </div> | ||
| 147 | </form> | ||
| 148 | <i id="change-subdir" class="icon-pencil"></i> | ||
| 149 | <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span> | ||
| 150 | </dd> | ||
| 151 | <dt>Brach, tag or commit</dt> | ||
| 152 | <dd> | ||
| 153 | <span class="current-value">{{layerversion.commit}}</span> | ||
| 154 | <form style="display:none;"> | ||
| 155 | <div class="input-append"> | ||
| 156 | <input type="text" value="{{layerversion.commit}}"> | ||
| 157 | <button data-layer-prop="commit" class="btn change-btn" type="button">Save</button> | ||
| 158 | <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a> | ||
| 159 | </div> | ||
| 160 | </form> | ||
| 161 | <i class="icon-pencil"></i> | ||
| 162 | </dd> | ||
| 163 | <dt> | ||
| 164 | <i class="icon-question-sign get-help" title="The Yocto Project versions with which this layer is compatible. Currently Toaster supports Yocto Project 1.6 and 1.7"></i> | ||
| 165 | Yocto Project compatibility | ||
| 166 | </dt> | ||
| 167 | <dd> | ||
| 168 | <span class="current-value">{{layerversion.up_branch.name}}</span> | ||
| 169 | <form style="display:none"> | ||
| 170 | <div class="input-append"> | ||
| 171 | <select name="projectversion" id="projectversion"> | ||
| 172 | {% for compat in yocto_compat %} | ||
| 173 | <option value="{{compat.id}}" {%if layerversion.up_branch.id == compat.id %} selected{%endif%}>{{compat.name}}</option> | ||
| 174 | {% endfor %} | ||
| 175 | </select> | ||
| 176 | <button data-layer-prop="up_branch" class="btn change-btn" type="button">Save</button> | ||
| 177 | <a href="#" style="display:none" class="btn btn-link cancel">Cancel</a> | ||
| 178 | </div> | ||
| 179 | </form> | ||
| 180 | <i class="icon-pencil"></i> | ||
| 181 | </dd> | ||
| 182 | <dt> | ||
| 183 | <i class="icon-question-sign get-help" title="Other layers this layer depends upon"></i> | ||
| 184 | Layer dependencies | ||
| 185 | </dt> | ||
| 186 | <dd> | ||
| 187 | <ul class="unstyled" id="layer-deps-list"> | ||
| 188 | {% for ld in layerversion.dependencies.all %} | ||
| 189 | <span class="current-value"> | ||
| 190 | <li data-layer-id="{{ld.depends_on.id}}"> | ||
| 191 | <!-- TODO use ld.depends_on.get_vcs_reference instead of commit --> | ||
| 192 | <a data-toggle="tooltip" title="{{ld.depends_on.layer.vcs_url}} | {{ld.depends_on.commit}}" href="{% url 'layerdetails' ld.depends_on.id %}">{{ld.depends_on.layer.name}}</a> | ||
| 193 | <span class="icon-trash " data-toggle="tooltip" title="Delete"></span> | ||
| 194 | </li> | ||
| 195 | </span> | ||
| 196 | {% endfor %} | ||
| 197 | </ul> | ||
| 198 | <div class="input-append add-deps"> | ||
| 199 | <input type="text" autocomplete="off" data-minLength="1" data-autocomplete="off" placeholder="Type a layer name" id="layer-dep-input"> | ||
| 200 | <a class="btn" type="button" id="add-layer-dependency-btn" disabled> | ||
| 201 | Add layer | ||
| 202 | </a> | ||
| 203 | </div> | ||
| 204 | <span class="help-block add-deps">You can only add layers Toaster knows about</span> | ||
| 205 | </dd> | ||
| 206 | </dl> | ||
| 207 | </div> | ||
| 208 | <!-- targets tab --> | ||
| 209 | <div name="targets" id="targets" class="tab-pane"> | ||
| 210 | {% if total_targets == 0 %} | ||
| 211 | <div class="alert alert-info"> | ||
| 212 | <strong>There is no target data for {{layerversion.layer.name}} ... yet</strong> <br /> | ||
| 213 | Toaster learns about layers as they are built. Once you have used {{layerversion.layer.name}} in a build, Toaster will show you | ||
| 214 | here the targets it provides. | ||
| 215 | </div> | ||
| 216 | {% else %} | ||
| 217 | |||
| 218 | <div class="row-fluid"> | ||
| 219 | |||
| 220 | {% if targets.paginator.count == 0 %} | ||
| 221 | <div class="alert"> | ||
| 222 | <h3>No targets found</h3> | ||
| 223 | {% endif %} | ||
| 224 | |||
| 225 | {# only show the search form if we have more than 10 results #} | ||
| 226 | {% if targets.paginator.count > 10 or request.GET.targets_search %} | ||
| 227 | {% if targets.paginator.count == 0 %} | ||
| 228 | <form class="input-append"> | ||
| 229 | {% else %} | ||
| 230 | <form class="navbar-search input-append pull-left"> | ||
| 231 | {% endif %} | ||
| 232 | |||
| 233 | <input type="text" id="target-search" name="targets_search" placeholder="Search targets" class="input-xlarge" value="{{request.GET.targets_search}}"> | ||
| 234 | {% if request.GET.targets_search %} | ||
| 235 | <a class="add-on btn" id="target-search-clear"> | ||
| 236 | <i class="icon-remove"></i> | ||
| 237 | </a> | ||
| 238 | {% endif %} | ||
| 239 | <button type="submit" class="btn">Search</button> | ||
| 240 | </form> | ||
| 241 | {% endif %} | ||
| 242 | |||
| 243 | {% if targets.paginator.count == 0 %} | ||
| 244 | <!-- end alert --> | ||
| 245 | </div> | ||
| 246 | <!-- end row-fluid --> | ||
| 247 | </div> | ||
| 248 | {% else %} | ||
| 249 | |||
| 250 | <div class="pull-right"> | ||
| 251 | <span class="help-inline" style="padding-top:5px;">Show rows:</span> | ||
| 252 | <select style="margin-top:5px;margin-bottom:0px;" class="pagesize"> | ||
| 253 | {% with "10 25 50 100 150" as list%} | ||
| 254 | {% for i in list.split %} | ||
| 255 | {% if request.session.limit == i %} | ||
| 256 | <option value="{{i}}" selected>{{i}}</option> | ||
| 257 | {% else %} | ||
| 258 | <option value="{{i}}">{{i}}</option> | ||
| 259 | {% endif %} | ||
| 260 | {% endfor %} | ||
| 261 | {% endwith %} | ||
| 262 | </select> | ||
| 263 | </div> | ||
| 264 | </div> | ||
| 265 | |||
| 266 | <table class="table table-bordered table-hover"> | ||
| 267 | <thead> | ||
| 268 | <tr> | ||
| 269 | <th> | ||
| 270 | <i class="icon-question-sign get-help" title="Information about a single piece of software, including where to download the source, configuration options, how to compile the source files and how to package the compiled output"></i> | ||
| 271 | Target | ||
| 272 | {% if request.GET.targets_search %} | ||
| 273 | <span class="badge badge-info">{{targets.paginator.count}}</span> | ||
| 274 | {% endif %} | ||
| 275 | </th> | ||
| 276 | <th> | ||
| 277 | <i class="icon-question-sign get-help" title="The recipe version and revision"></i> | ||
| 278 | Target version | ||
| 279 | </th> | ||
| 280 | <th class="span4">Description</th> | ||
| 281 | <th>Build target</th> | ||
| 282 | </tr> | ||
| 283 | </thead> | ||
| 284 | <tbody> | ||
| 285 | {% for target in targets %} | ||
| 286 | <tr> | ||
| 287 | <td> | ||
| 288 | {{target.name}} | ||
| 289 | {% if target.up_id %} | ||
| 290 | <a href="http://layers.openembedded.org/layerindex/recipe/{{target.up_id}}/" class="icon-share get-info"></a> | ||
| 291 | {% endif %} | ||
| 292 | </td> | ||
| 293 | <td>{{target.version}}</td> | ||
| 294 | <td>{{target.summary}}</td> | ||
| 295 | <td><button class="btn btn-block build-target-btn" data-target-name="{{target.name}}" {% if layer_in_project == 0 %}disabled="disabled"{% endif %} >Build Target</button></td> | ||
| 296 | </tr> | ||
| 297 | {% endfor %} | ||
| 298 | </tbody> | ||
| 299 | </table> | ||
| 300 | |||
| 301 | <!-- Show pagination controls --> | ||
| 302 | <div class="pagination"> | ||
| 303 | <ul> | ||
| 304 | {%if targets.has_previous %} | ||
| 305 | <li><a href="?tpage={{targets.previous_page_number}}{{request.GET.limit}}#targets">«</a></li> | ||
| 306 | {%else%} | ||
| 307 | <li class="disabled"><a href="#">«</a></li> | ||
| 308 | {%endif%} | ||
| 309 | {% for i in targets.paginator.page_range %} | ||
| 310 | <li {%if i == targets.number %} class="active" {%endif%}><a href="?tpage={{i}}#targets">{{i}}</a></li> | ||
| 311 | {% endfor %} | ||
| 312 | {%if targets.has_next%} | ||
| 313 | <li><a href="?tpage={{targets.next_page_number}}#targets">»</a></li> | ||
| 314 | {%else%} | ||
| 315 | <li class="disabled"><a href="#">»</a></li> | ||
| 316 | {%endif%} | ||
| 317 | </ul> | ||
| 318 | <div class="pull-right"> | ||
| 319 | <span class="help-inline" style="padding-top:5px;">Show rows:</span> | ||
| 320 | <select style="margin-top:5px;margin-bottom:0px;" class="pagesize"> | ||
| 321 | {% with "10 25 50 100 150" as list%} | ||
| 322 | {% for i in list.split %} | ||
| 323 | {% if request.session.limit == i %} | ||
| 324 | <option value="{{i}}" selected>{{i}}</option> | ||
| 325 | {% else %} | ||
| 326 | <option value="{{i}}">{{i}}</option> | ||
| 327 | {% endif %} | ||
| 328 | {% endfor %} | ||
| 329 | {% endwith %} | ||
| 330 | </select> | ||
| 331 | </div> | ||
| 332 | </div> | ||
| 333 | {% endif %} | ||
| 334 | {% endif %} | ||
| 335 | </div> | ||
| 336 | |||
| 337 | |||
| 338 | <div name="machines" id="machines" class="tab-pane"> | ||
| 339 | {% if total_machines == 0 %} | ||
| 340 | <div class="alert alert-info"> | ||
| 341 | <strong>There is no machine data for {{layerversion.layer.name}} ... yet</strong> <br /> | ||
| 342 | Toaster learns about layers as they are built. Once you have used {{layerversion.layer.name}} in a build, Toaster will show you | ||
| 343 | here the machines it provides. | ||
| 344 | </div> | ||
| 345 | {% else %} | ||
| 346 | |||
| 347 | <div class="row-fluid"> | ||
| 348 | |||
| 349 | {% if machines.paginator.count == 0 %} | ||
| 350 | <div class="alert"> | ||
| 351 | <h3>No machines found</h3> | ||
| 352 | {% endif %} | ||
| 353 | |||
| 354 | {# only show the search form if we have more than 10 results #} | ||
| 355 | {% if machines.paginator.count > 10 or request.GET.machines_search %} | ||
| 356 | {% if machines.paginator.count == 0 %} | ||
| 357 | <form class="input-append"> | ||
| 358 | {% else %} | ||
| 359 | <form class="navbar-search input-append pull-left"> | ||
| 360 | {% endif %} | ||
| 361 | |||
| 362 | <input type="text" id="machine-search" name="machines_search" placeholder="Search machines" class="input-xlarge" value="{{request.GET.machines_search}}"> | ||
| 363 | {% if request.GET.machines_search %} | ||
| 364 | <a class="add-on btn" id="machine-search-clear"> | ||
| 365 | <i class="icon-remove"></i> | ||
| 366 | </a> | ||
| 367 | {% endif %} | ||
| 368 | <button type="submit" class="btn">Search</button> | ||
| 369 | </form> | ||
| 370 | {% endif %} | ||
| 371 | |||
| 372 | {% if machines.paginator.count == 0 %} | ||
| 373 | <!-- end alert --> | ||
| 374 | </div> | ||
| 375 | <!-- end row-fluid --> | ||
| 376 | </div> | ||
| 377 | {% else %} | ||
| 378 | |||
| 379 | <div class="pull-right"> | ||
| 380 | <span class="help-inline" style="padding-top:5px;">Show rows:</span> | ||
| 381 | <select style="margin-top:5px;margin-bottom:0px;" class="pagesize"> | ||
| 382 | {% with "10 25 50 100 150" as list%} | ||
| 383 | {% for i in list.split %} | ||
| 384 | {% if request.session.limit == i %} | ||
| 385 | <option value="{{i}}" selected>{{i}}</option> | ||
| 386 | {% else %} | ||
| 387 | <option value="{{i}}">{{i}}</option> | ||
| 388 | {% endif %} | ||
| 389 | {% endfor %} | ||
| 390 | {% endwith %} | ||
| 391 | </select> | ||
| 392 | </div> | ||
| 393 | </div> | ||
| 394 | |||
| 395 | <table class="table table-bordered table-hover"> | ||
| 396 | <thead> | ||
| 397 | <tr> | ||
| 398 | <th> | ||
| 399 | <i class="icon-question-sign get-help" title="The machine is the hardware for which you are building"></i> | ||
| 400 | Machine | ||
| 401 | {% if request.GET.machines_search %} | ||
| 402 | <span class="badge badge-info">{{machines.paginator.count}}</span> | ||
| 403 | {% endif %} | ||
| 404 | </th> | ||
| 405 | <th>Description</th> | ||
| 406 | <th>Select machine</th> | ||
| 407 | </tr> | ||
| 408 | </thead> | ||
| 409 | <tbody> | ||
| 410 | {% for machine in machines %} | ||
| 411 | <tr> | ||
| 412 | <td>{{machine.name}}</td> | ||
| 413 | <td>{{machine.description}}</td> | ||
| 414 | <td><button class="btn btn-block select-machine-btn" data-machine-name="{{machine.name}}" {% if layer_in_project == 0 %}disabled="disabled"{% endif %}}>Select machine</button></td> | ||
| 415 | </tr> | ||
| 416 | {% endfor %} | ||
| 417 | </tbody> | ||
| 418 | </table> | ||
| 419 | |||
| 420 | <!-- Show pagination controls --> | ||
| 421 | <div class="pagination"> | ||
| 422 | <ul> | ||
| 423 | {%if machines.has_previous %} | ||
| 424 | <li><a href="?mpage={{machines.previous_page_number}}{{request.GET.limit}}#machines">«</a></li> | ||
| 425 | {%else%} | ||
| 426 | <li class="disabled"><a href="#">«</a></li> | ||
| 427 | {%endif%} | ||
| 428 | {% for i in machines.paginator.page_range %} | ||
| 429 | <li {%if i == machines.number %} class="active" {%endif%}><a href="?mpage={{i}}#machines">{{i}}</a></li> | ||
| 430 | {% endfor %} | ||
| 431 | {%if machines.has_next%} | ||
| 432 | <li><a href="?mpage={{machines.next_page_number}}#machines">»</a></li> | ||
| 433 | {%else%} | ||
| 434 | <li class="disabled"><a href="#">»</a></li> | ||
| 435 | {%endif%} | ||
| 436 | </ul> | ||
| 437 | <div class="pull-right"> | ||
| 438 | <span class="help-inline" style="padding-top:5px;">Show rows:</span> | ||
| 439 | <select style="margin-top:5px;margin-bottom:0px;" class="pagesize"> | ||
| 440 | {% with "10 25 50 100 150" as list%} | ||
| 441 | {% for i in list.split %} | ||
| 442 | {% if request.session.limit == i %} | ||
| 443 | <option value="{{i}}" selected>{{i}}</option> | ||
| 444 | {% else %} | ||
| 445 | <option value="{{i}}">{{i}}</option> | ||
| 446 | {% endif %} | ||
| 447 | {% endfor %} | ||
| 448 | {% endwith %} | ||
| 449 | </select> | ||
| 450 | </div> | ||
| 451 | </div> | ||
| 452 | {% endif %} | ||
| 453 | {% endif %} | ||
| 454 | </div> | ||
| 455 | </div> | ||
| 456 | </div> | ||
| 457 | <div class="row span4 well"> | ||
| 458 | <h2>About {{layerversion.layer.name}}</h2> | ||
| 459 | <dl> | ||
| 460 | |||
| 461 | <dt> | ||
| 462 | Summary | ||
| 463 | <i class="icon-question-sign get-help" title="One-line description of the layer"></i> | ||
| 464 | </dt> | ||
| 465 | <dd> | ||
| 466 | <span class="muted" style="display:none">Not set</span> | ||
| 467 | <span class="current-value">{{layerversion.layer.summary}}</span> | ||
| 468 | <form style="display:none; margin-bottom:20px"> | ||
| 469 | <textarea class="span12" rows="2">{% if layerversion.layer.summary %}{{layerversion.layer.summary}}{% endif %}</textarea> | ||
| 470 | <button class="btn change-btn" data-layer-prop="summary" type="button">Save</button> | ||
| 471 | <a href="#" class="btn btn-link cancel">Cancel</a> | ||
| 472 | </form> | ||
| 473 | <i class="icon-pencil"></i> | ||
| 474 | <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span> | ||
| 475 | </dd> | ||
| 476 | <dt> | ||
| 477 | Description | ||
| 478 | </dt> | ||
| 479 | <dd> | ||
| 480 | <span class="muted" style="display:none">Not set</span> | ||
| 481 | <span class="current-value">{{layerversion.layer.description}}</span> | ||
| 482 | <form style="display:none; margin-bottom:20px"> | ||
| 483 | <textarea class="span12" rows="6">{% if layerversion.layer.description %}{{layerversion.layer.description}}{% endif %}</textarea> | ||
| 484 | <button class="btn change-btn" data-layer-prop="description" type="button" >Save</button> | ||
| 485 | <a href="#" class="btn btn-link cancel">Cancel</a> | ||
| 486 | </form> | ||
| 487 | <i class="icon-pencil"></i> | ||
| 488 | <span class="icon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span> | ||
| 489 | </dd> | ||
| 490 | </dd> | ||
| 491 | {% if layerversion.layer.up_id %} | ||
| 492 | <dt>Layer index</dt> | ||
| 493 | <dd> | ||
| 494 | <a href="http://layers.openembedded.org/layerindex/branch/{{layerversion.up_branch.name}}/layer/{{layerversion.layer.name}}"/>layer index link</a> | ||
| 495 | |||
| 496 | </dd> | ||
| 497 | {% endif %} | ||
| 157 | 498 | ||
| 499 | </dl> | ||
| 500 | </div> | ||
| 158 | 501 | ||
| 502 | </div> | ||
| 503 | </div> | ||
| 504 | </div> | ||
| 159 | {% endblock %} | 505 | {% endblock %} |
diff --git a/bitbake/lib/toaster/toastergui/templates/layers_dep_modal.html b/bitbake/lib/toaster/toastergui/templates/layers_dep_modal.html index b03fd0b218..8222027d4f 100644 --- a/bitbake/lib/toaster/toastergui/templates/layers_dep_modal.html +++ b/bitbake/lib/toaster/toastergui/templates/layers_dep_modal.html | |||
| @@ -18,7 +18,16 @@ | |||
| 18 | </div> | 18 | </div> |
| 19 | 19 | ||
| 20 | <script> | 20 | <script> |
| 21 | /* projectId: current project | ||
| 22 | * layer: Object representing the parent layer { id: .. name: ... url } | ||
| 23 | * dependencies: array of dependency layer objects { id: .. name: ..} | ||
| 24 | * title: optional override for title | ||
| 25 | * body: optional override for body | ||
| 26 | * addToProject: Whether to add layers to project on accept | ||
| 27 | * successAdd: function to run on success | ||
| 28 | */ | ||
| 21 | function show_layer_deps_modal(projectId, layer, dependencies, title, body, addToProject, successAdd) { | 29 | function show_layer_deps_modal(projectId, layer, dependencies, title, body, addToProject, successAdd) { |
| 30 | |||
| 22 | // update layer name | 31 | // update layer name |
| 23 | if (title) { | 32 | if (title) { |
| 24 | $('#dependencies_modal #title').text(title); | 33 | $('#dependencies_modal #title').text(title); |
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 6e1b0ab913..5c969f814c 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
| @@ -94,6 +94,7 @@ urlpatterns = patterns('toastergui.views', | |||
| 94 | 94 | ||
| 95 | url(r'^xhr_datatypeahead/$', 'xhr_datatypeahead', name='xhr_datatypeahead'), | 95 | url(r'^xhr_datatypeahead/$', 'xhr_datatypeahead', name='xhr_datatypeahead'), |
| 96 | url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'), | 96 | url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'), |
| 97 | url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'), | ||
| 97 | 98 | ||
| 98 | 99 | ||
| 99 | # default redirection | 100 | # default redirection |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 8c21ca48e0..7a9d662b31 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -2336,6 +2336,50 @@ if toastermain.settings.MANAGED: | |||
| 2336 | 2336 | ||
| 2337 | return HttpResponse(jsonfilter({"error": "ok", "imported_layer" : { "name" : layer.name, "id": layer_version.id }, "deps_added": layers_added }), content_type = "application/json") | 2337 | return HttpResponse(jsonfilter({"error": "ok", "imported_layer" : { "name" : layer.name, "id": layer_version.id }, "deps_added": layers_added }), content_type = "application/json") |
| 2338 | 2338 | ||
| 2339 | def xhr_updatelayer(request): | ||
| 2340 | |||
| 2341 | def error_response(error): | ||
| 2342 | return HttpResponse(jsonfilter({"error": error}), content_type = "application/json") | ||
| 2343 | |||
| 2344 | if not request.POST.has_key("layer_version_id"): | ||
| 2345 | return error_response("Please specify a layer version id") | ||
| 2346 | try: | ||
| 2347 | layer_version_id = request.POST["layer_version_id"] | ||
| 2348 | layer_version = Layer_Version.objects.get(id=layer_version_id) | ||
| 2349 | except: | ||
| 2350 | return error_response("Cannot find layer to update") | ||
| 2351 | |||
| 2352 | |||
| 2353 | if request.POST.has_key("vcs_url"): | ||
| 2354 | layer_version.layer.vcs_url = request.POST["vcs_url"] | ||
| 2355 | if request.POST.has_key("dirpath"): | ||
| 2356 | layer_version.dirpath = request.POST["dirpath"] | ||
| 2357 | if request.POST.has_key("commit"): | ||
| 2358 | layer_version.commit = request.POST["commit"] | ||
| 2359 | if request.POST.has_key("up_branch"): | ||
| 2360 | layer_version.up_branch_id = int(request.POST["up_branch"]) | ||
| 2361 | |||
| 2362 | if request.POST.has_key("add_dep"): | ||
| 2363 | lvd = LayerVersionDependency(layer_version=layer_version, depends_on_id=request.POST["add_dep"]) | ||
| 2364 | lvd.save() | ||
| 2365 | |||
| 2366 | if request.POST.has_key("rm_dep"): | ||
| 2367 | rm_dep = LayerVersionDependency.objects.get(layer_version=layer_version, depends_on_id=request.POST["rm_dep"]) | ||
| 2368 | rm_dep.delete() | ||
| 2369 | |||
| 2370 | if request.POST.has_key("summary"): | ||
| 2371 | layer_version.layer.summary = request.POST["summary"] | ||
| 2372 | if request.POST.has_key("description"): | ||
| 2373 | layer_version.layer.description = request.POST["description"] | ||
| 2374 | |||
| 2375 | try: | ||
| 2376 | layer_version.layer.save() | ||
| 2377 | layer_version.save() | ||
| 2378 | except: | ||
| 2379 | return error_response("Could not update layer version entry") | ||
| 2380 | |||
| 2381 | return HttpResponse(jsonfilter({"error": "ok",}), content_type = "application/json") | ||
| 2382 | |||
| 2339 | 2383 | ||
| 2340 | 2384 | ||
| 2341 | def importlayer(request): | 2385 | def importlayer(request): |
| @@ -2439,8 +2483,53 @@ if toastermain.settings.MANAGED: | |||
| 2439 | 2483 | ||
| 2440 | def layerdetails(request, layerid): | 2484 | def layerdetails(request, layerid): |
| 2441 | template = "layerdetails.html" | 2485 | template = "layerdetails.html" |
| 2486 | limit = 10 | ||
| 2487 | |||
| 2488 | if request.GET.has_key("limit"): | ||
| 2489 | request.session['limit'] = request.GET['limit'] | ||
| 2490 | |||
| 2491 | if request.session.has_key('limit'): | ||
| 2492 | limit = request.session['limit'] | ||
| 2493 | |||
| 2494 | layer_version = Layer_Version.objects.get(pk = layerid) | ||
| 2495 | |||
| 2496 | # Targets tab query functionality | ||
| 2497 | if request.GET.has_key('targets_search'): | ||
| 2498 | targets = Paginator(Recipe.objects.filter(layer_version=layer_version,name__icontains=request.GET['targets_search']).order_by("name"), limit) | ||
| 2499 | else: | ||
| 2500 | targets = Paginator(Recipe.objects.filter(layer_version=layer_version).order_by("name"), limit) | ||
| 2501 | |||
| 2502 | if request.GET.has_key("tpage"): | ||
| 2503 | try: | ||
| 2504 | targets = targets.page(request.GET['tpage']) | ||
| 2505 | except EmptyPage: | ||
| 2506 | targets = targets.page(targets.num_pages) | ||
| 2507 | else: | ||
| 2508 | targets = targets.page(1) | ||
| 2509 | |||
| 2510 | # Machines tab query functionality | ||
| 2511 | if request.GET.has_key('machines_search'): | ||
| 2512 | machines = Paginator(Machine.objects.filter(layer_version=layer_version,name__icontains=request.GET['machines_search']).order_by("name"), limit) | ||
| 2513 | else: | ||
| 2514 | machines = Paginator(Machine.objects.filter(layer_version=layer_version).order_by("name"), limit) | ||
| 2515 | |||
| 2516 | if request.GET.has_key("mpage"): | ||
| 2517 | try: | ||
| 2518 | machines = machines.page(request.GET['mpage']) | ||
| 2519 | except EmptyPage: | ||
| 2520 | machines = machines.page(machines.num_pages) | ||
| 2521 | else: | ||
| 2522 | machines = machines.page(1) | ||
| 2523 | |||
| 2442 | context = { | 2524 | context = { |
| 2443 | 'layerversion': Layer_Version.objects.get(pk = layerid), | 2525 | 'layerversion': layer_version, |
| 2526 | 'layer_in_project' : ProjectLayer.objects.filter(project_id=request.session['project_id'],layercommit=layerid).count(), | ||
| 2527 | 'yocto_compat': Branch.objects.filter(layer_source=layer_version.layer_source), | ||
| 2528 | 'machines': machines, | ||
| 2529 | 'targets': targets, | ||
| 2530 | 'total_targets': Recipe.objects.filter(layer_version=layer_version).count(), | ||
| 2531 | |||
| 2532 | 'total_machines': Machine.objects.filter(layer_version=layer_version).count(), | ||
| 2444 | } | 2533 | } |
| 2445 | return render(request, template, context) | 2534 | return render(request, template, context) |
| 2446 | 2535 | ||
| @@ -2972,3 +3061,6 @@ else: | |||
| 2972 | 3061 | ||
| 2973 | def xhr_importlayer(request): | 3062 | def xhr_importlayer(request): |
| 2974 | raise Exception("page not available in interactive mode") | 3063 | raise Exception("page not available in interactive mode") |
| 3064 | |||
| 3065 | def xhr_updatelayer(request): | ||
| 3066 | raise Exception("page not available in interactive mode") | ||
