diff options
| -rw-r--r-- | bitbake/lib/toaster/toastergui/api.py | 161 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/libtoaster.js | 3 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/projectpage.js | 147 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/tests/test.js | 7 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/base.html | 1 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/urls.py | 4 | ||||
| -rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 131 |
7 files changed, 179 insertions, 275 deletions
diff --git a/bitbake/lib/toaster/toastergui/api.py b/bitbake/lib/toaster/toastergui/api.py index be18090daf..8876409964 100644 --- a/bitbake/lib/toaster/toastergui/api.py +++ b/bitbake/lib/toaster/toastergui/api.py | |||
| @@ -20,11 +20,13 @@ | |||
| 20 | 20 | ||
| 21 | import re | 21 | import re |
| 22 | import logging | 22 | import logging |
| 23 | from collections import Counter | ||
| 23 | 24 | ||
| 24 | from orm.models import Project, ProjectTarget, Build, Layer_Version | 25 | from orm.models import Project, ProjectTarget, Build, Layer_Version |
| 25 | from orm.models import LayerVersionDependency, LayerSource, ProjectLayer | 26 | from orm.models import LayerVersionDependency, LayerSource, ProjectLayer |
| 26 | from orm.models import Recipe, CustomImageRecipe, CustomImagePackage | 27 | from orm.models import Recipe, CustomImageRecipe, CustomImagePackage |
| 27 | from orm.models import Layer, Target, Package, Package_Dependency | 28 | from orm.models import Layer, Target, Package, Package_Dependency |
| 29 | from orm.models import ProjectVariable | ||
| 28 | from bldcontrol.models import BuildRequest | 30 | from bldcontrol.models import BuildRequest |
| 29 | from bldcontrol import bbcontroller | 31 | from bldcontrol import bbcontroller |
| 30 | 32 | ||
| @@ -772,3 +774,162 @@ class XhrCustomRecipePackages(View): | |||
| 772 | except CustomImageRecipe.DoesNotExist: | 774 | except CustomImageRecipe.DoesNotExist: |
| 773 | return error_response("Tried to remove package that wasn't" | 775 | return error_response("Tried to remove package that wasn't" |
| 774 | " present") | 776 | " present") |
| 777 | |||
| 778 | |||
| 779 | class XhrProject(View): | ||
| 780 | """ Create, delete or edit a project | ||
| 781 | |||
| 782 | Entry point: /xhr_project/<project_id> | ||
| 783 | """ | ||
| 784 | def post(self, request, *args, **kwargs): | ||
| 785 | """ | ||
| 786 | Edit project control | ||
| 787 | |||
| 788 | Args: | ||
| 789 | layerAdd = layer_version_id layer_version_id ... | ||
| 790 | layerDel = layer_version_id layer_version_id ... | ||
| 791 | projectName = new_project_name | ||
| 792 | machineName = new_machine_name | ||
| 793 | |||
| 794 | Returns: | ||
| 795 | {"error": "ok"} | ||
| 796 | or | ||
| 797 | {"error": <error message>} | ||
| 798 | """ | ||
| 799 | try: | ||
| 800 | prj = Project.objects.get(pk=kwargs['project_id']) | ||
| 801 | except Project.DoesNotExist: | ||
| 802 | return error_response("No such project") | ||
| 803 | |||
| 804 | # Add layers | ||
| 805 | if 'layerAdd' in request.POST and len(request.POST['layerAdd']) > 0: | ||
| 806 | for layer_version_id in request.POST['layerAdd'].split(','): | ||
| 807 | try: | ||
| 808 | lv = Layer_Version.objects.get(pk=int(layer_version_id)) | ||
| 809 | ProjectLayer.objects.get_or_create(project=prj, | ||
| 810 | layercommit=lv) | ||
| 811 | except Layer_Version.DoesNotExist: | ||
| 812 | return error_response("Layer version %s asked to add " | ||
| 813 | "doesn't exist" % layer_version_id) | ||
| 814 | |||
| 815 | # Remove layers | ||
| 816 | if 'layerDel' in request.POST and len(request.POST['layerDel']) > 0: | ||
| 817 | layer_version_ids = request.POST['layerDel'].split(',') | ||
| 818 | ProjectLayer.objects.filter( | ||
| 819 | project=prj, | ||
| 820 | layercommit_id__in=layer_version_ids).delete() | ||
| 821 | |||
| 822 | # Project name change | ||
| 823 | if 'projectName' in request.POST: | ||
| 824 | prj.name = request.POST['projectName'] | ||
| 825 | prj.save() | ||
| 826 | |||
| 827 | # Machine name change | ||
| 828 | if 'machineName' in request.POST: | ||
| 829 | machinevar = prj.projectvariable_set.get(name="MACHINE") | ||
| 830 | machinevar.value = request.POST['machineName'] | ||
| 831 | machinevar.save() | ||
| 832 | |||
| 833 | return JsonResponse({"error": "ok"}) | ||
| 834 | |||
| 835 | def get(self, request, *args, **kwargs): | ||
| 836 | """ | ||
| 837 | Returns: | ||
| 838 | json object representing the current project | ||
| 839 | or: | ||
| 840 | {"error": <error message>} | ||
| 841 | """ | ||
| 842 | |||
| 843 | try: | ||
| 844 | project = Project.objects.get(pk=kwargs['project_id']) | ||
| 845 | except Project.DoesNotExist: | ||
| 846 | return error_response("Project %s does not exist" % | ||
| 847 | kwargs['project_id']) | ||
| 848 | |||
| 849 | # Create the frequently built targets list | ||
| 850 | |||
| 851 | freqtargets = Counter(Target.objects.filter( | ||
| 852 | Q(build__project=project), | ||
| 853 | ~Q(build__outcome=Build.IN_PROGRESS) | ||
| 854 | ).order_by("target").values_list("target", flat=True)) | ||
| 855 | |||
| 856 | freqtargets = freqtargets.most_common(5) | ||
| 857 | |||
| 858 | # We now have the targets in order of frequency but if there are two | ||
| 859 | # with the same frequency then we need to make sure those are in | ||
| 860 | # alphabetical order without losing the frequency ordering | ||
| 861 | |||
| 862 | tmp = [] | ||
| 863 | switch = None | ||
| 864 | for i, freqtartget in enumerate(freqtargets): | ||
| 865 | target, count = freqtartget | ||
| 866 | try: | ||
| 867 | target_next, count_next = freqtargets[i+1] | ||
| 868 | if count == count_next and target > target_next: | ||
| 869 | switch = target | ||
| 870 | continue | ||
| 871 | except IndexError: | ||
| 872 | pass | ||
| 873 | |||
| 874 | tmp.append(target) | ||
| 875 | |||
| 876 | if switch: | ||
| 877 | tmp.append(switch) | ||
| 878 | switch = None | ||
| 879 | |||
| 880 | freqtargets = tmp | ||
| 881 | |||
| 882 | layers = [] | ||
| 883 | for layer in project.projectlayer_set.all(): | ||
| 884 | layers.append({ | ||
| 885 | "id": layer.layercommit.pk, | ||
| 886 | "name": layer.layercommit.layer.name, | ||
| 887 | "vcs_url": layer.layercommit.layer.vcs_url, | ||
| 888 | "local_source_dir": layer.layercommit.layer.local_source_dir, | ||
| 889 | "vcs_reference": layer.layercommit.get_vcs_reference(), | ||
| 890 | "url": layer.layercommit.layer.layer_index_url, | ||
| 891 | "layerdetailurl": layer.layercommit.get_detailspage_url( | ||
| 892 | project.pk), | ||
| 893 | "layersource": layer.layercommit.layer_source | ||
| 894 | }) | ||
| 895 | |||
| 896 | data = { | ||
| 897 | "name": project.name, | ||
| 898 | "layers": layers, | ||
| 899 | "freqtargets": freqtargets, | ||
| 900 | } | ||
| 901 | |||
| 902 | if project.release is not None: | ||
| 903 | data['release'] = { | ||
| 904 | "id": project.release.pk, | ||
| 905 | "name": project.release.name, | ||
| 906 | "description": project.release.description | ||
| 907 | } | ||
| 908 | |||
| 909 | try: | ||
| 910 | data["machine"] = {"name": | ||
| 911 | project.projectvariable_set.get( | ||
| 912 | name="MACHINE").value} | ||
| 913 | except ProjectVariable.DoesNotExist: | ||
| 914 | data["machine"] = None | ||
| 915 | try: | ||
| 916 | data["distro"] = project.projectvariable_set.get( | ||
| 917 | name="DISTRO").value | ||
| 918 | except ProjectVariable.DoesNotExist: | ||
| 919 | data["distro"] = "-- not set yet" | ||
| 920 | |||
| 921 | data['error'] = "ok" | ||
| 922 | |||
| 923 | return JsonResponse(data) | ||
| 924 | |||
| 925 | def put(self, request, *args, **kwargs): | ||
| 926 | # TODO create new project api | ||
| 927 | return HttpResponse() | ||
| 928 | |||
| 929 | def delete(self, request, *args, **kwargs): | ||
| 930 | try: | ||
| 931 | Project.objects.get(kwargs['project_id']).delete() | ||
| 932 | except Project.DoesNotExist: | ||
| 933 | return error_response("Project %s does not exist" % | ||
| 934 | kwargs['project_id']) | ||
| 935 | return JsonResponse({"error": "ok"}) | ||
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js index f56affd8ea..b2099a6048 100644 --- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js +++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js | |||
| @@ -167,7 +167,6 @@ var libtoaster = (function () { | |||
| 167 | function _getProjectInfo(url, onsuccess, onfail){ | 167 | function _getProjectInfo(url, onsuccess, onfail){ |
| 168 | $.ajax({ | 168 | $.ajax({ |
| 169 | type: "GET", | 169 | type: "GET", |
| 170 | data : { format: "json" }, | ||
| 171 | url: url, | 170 | url: url, |
| 172 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, | 171 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, |
| 173 | success: function (_data) { | 172 | success: function (_data) { |
| @@ -194,7 +193,7 @@ var libtoaster = (function () { | |||
| 194 | function _editCurrentProject(data, onSuccess, onFail){ | 193 | function _editCurrentProject(data, onSuccess, onFail){ |
| 195 | $.ajax({ | 194 | $.ajax({ |
| 196 | type: "POST", | 195 | type: "POST", |
| 197 | url: libtoaster.ctx.projectPageUrl + "?format=json", | 196 | url: libtoaster.ctx.xhrProjectUrl, |
| 198 | data: data, | 197 | data: data, |
| 199 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, | 198 | headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, |
| 200 | success: function (data) { | 199 | success: function (data) { |
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectpage.js b/bitbake/lib/toaster/toastergui/static/js/projectpage.js index b75b3e1869..3bf3cbaf2b 100644 --- a/bitbake/lib/toaster/toastergui/static/js/projectpage.js +++ b/bitbake/lib/toaster/toastergui/static/js/projectpage.js | |||
| @@ -27,11 +27,10 @@ function projectPageInit(ctx) { | |||
| 27 | 27 | ||
| 28 | var urlParams = libtoaster.parseUrlParams(); | 28 | var urlParams = libtoaster.parseUrlParams(); |
| 29 | 29 | ||
| 30 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ | 30 | libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl, function(prjInfo){ |
| 31 | updateProjectLayers(prjInfo.layers); | 31 | updateProjectLayers(prjInfo.layers); |
| 32 | updateFreqBuildRecipes(prjInfo.freqtargets); | 32 | updateFreqBuildRecipes(prjInfo.freqtargets); |
| 33 | updateProjectRelease(prjInfo.release); | 33 | updateProjectRelease(prjInfo.release); |
| 34 | updateProjectReleases(prjInfo.releases, prjInfo.release); | ||
| 35 | 34 | ||
| 36 | /* If we're receiving a machine set from the url and it's different from | 35 | /* If we're receiving a machine set from the url and it's different from |
| 37 | * our current machine then activate set machine sequence. | 36 | * our current machine then activate set machine sequence. |
| @@ -287,7 +286,9 @@ function projectPageInit(ctx) { | |||
| 287 | machineNameTitle.text(machineName); | 286 | machineNameTitle.text(machineName); |
| 288 | } | 287 | } |
| 289 | 288 | ||
| 290 | libtoaster.makeTypeahead(machineChangeInput, libtoaster.ctx.machinesTypeAheadUrl, { }, function(item){ | 289 | libtoaster.makeTypeahead(machineChangeInput, |
| 290 | libtoaster.ctx.machinesTypeAheadUrl, | ||
| 291 | { }, function(item){ | ||
| 291 | currentMachineAddSelection = item.name; | 292 | currentMachineAddSelection = item.name; |
| 292 | machineChangeBtn.removeAttr("disabled"); | 293 | machineChangeBtn.removeAttr("disabled"); |
| 293 | }); | 294 | }); |
| @@ -324,146 +325,10 @@ function projectPageInit(ctx) { | |||
| 324 | releaseTitle.text(release.description); | 325 | releaseTitle.text(release.description); |
| 325 | } | 326 | } |
| 326 | 327 | ||
| 327 | function updateProjectReleases(releases, current){ | ||
| 328 | for (var i in releases){ | ||
| 329 | var releaseOption = $("<option></option>"); | ||
| 330 | 328 | ||
| 331 | releaseOption.val(releases[i].id); | 329 | $("#delete-project-confirmed").click(function(e){ |
| 332 | releaseOption.text(releases[i].description); | ||
| 333 | releaseOption.data('release', releases[i]); | ||
| 334 | |||
| 335 | if (releases[i].id == current.id) | ||
| 336 | releaseOption.attr("selected", "selected"); | ||
| 337 | |||
| 338 | releaseForm.children("select").append(releaseOption); | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | releaseChangeFormToggle.click(function(){ | ||
| 343 | releaseForm.slideDown(); | ||
| 344 | releaseTitle.hide(); | ||
| 345 | $(this).hide(); | ||
| 346 | }); | ||
| 347 | |||
| 348 | cancelReleaseChange.click(function(e){ | ||
| 349 | e.preventDefault(); | 330 | e.preventDefault(); |
| 350 | releaseForm.slideUp(function(){ | 331 | |
| 351 | releaseTitle.show(); | ||
| 352 | releaseChangeFormToggle.show(); | ||
| 353 | }); | ||
| 354 | }); | ||
| 355 | |||
| 356 | function changeProjectRelease(release, layersToRm){ | ||
| 357 | libtoaster.editCurrentProject({ projectVersion : release.id }, | ||
| 358 | function(){ | ||
| 359 | /* Success */ | ||
| 360 | /* Update layers list with new layers */ | ||
| 361 | layersInPrjList.addClass('muted'); | ||
| 362 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, | ||
| 363 | function(prjInfo){ | ||
| 364 | layersInPrjList.children().remove(); | ||
| 365 | updateProjectLayers(prjInfo.layers); | ||
| 366 | layersInPrjList.removeClass('muted'); | ||
| 367 | releaseChangedNotification(release, prjInfo.layers, layersToRm); | ||
| 368 | }); | ||
| 369 | updateProjectRelease(release); | ||
| 370 | cancelReleaseChange.click(); | ||
| 371 | }); | ||
| 372 | } | ||
| 373 | |||
| 374 | /* Create a notification to show the changes to the layer configuration | ||
| 375 | * caused by changing a release. | ||
| 376 | */ | ||
| 377 | |||
| 378 | function releaseChangedNotification(release, layers, layersToRm){ | ||
| 379 | |||
| 380 | var message; | ||
| 381 | |||
| 382 | if (layers.length === 0 && layersToRm.length === 0){ | ||
| 383 | message = $('<span><span class="lead">You have changed the project release to: <strong><span id="notify-release-name"></span></strong>.'); | ||
| 384 | message.find("#notify-release-name").text(release.description); | ||
| 385 | libtoaster.showChangeNotification(message); | ||
| 386 | return; | ||
| 387 | } | ||
| 388 | |||
| 389 | /* Create the whitespace separated list of layers removed */ | ||
| 390 | var layersDelList = ""; | ||
| 391 | |||
| 392 | layersToRm.map(function(layer, i){ | ||
| 393 | layersDelList += layer.name; | ||
| 394 | if (layersToRm[i+1] !== undefined) | ||
| 395 | layersDelList += ', '; | ||
| 396 | }); | ||
| 397 | |||
| 398 | 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>'); | ||
| 399 | |||
| 400 | var changedList = message.find("#notify-layers-changed-list"); | ||
| 401 | |||
| 402 | message.find("#notify-release-name").text(release.description); | ||
| 403 | |||
| 404 | /* Manually construct the list item for changed layers */ | ||
| 405 | var li = '<li><strong>'+layers.length+'</strong> layers changed to the <strong>'+release.name+'</strong> release: '; | ||
| 406 | for (var i in layers){ | ||
| 407 | li += '<a href='+layers[i].layerdetailurl+'>'+layers[i].name+'</a>'; | ||
| 408 | if (i !== 0) | ||
| 409 | li += ', '; | ||
| 410 | } | ||
| 411 | |||
| 412 | changedList.append($(li)); | ||
| 413 | |||
| 414 | /* Layers removed */ | ||
| 415 | if (layersToRm && layersToRm.length > 0){ | ||
| 416 | if (layersToRm.length == 1) | ||
| 417 | li = '<li><strong>1</strong> layer removed: '+layersToRm[0].name+'</li>'; | ||
| 418 | else | ||
| 419 | li = '<li><strong>'+layersToRm.length+'</strong> layers deleted: '+layersDelList+'</li>'; | ||
| 420 | |||
| 421 | changedList.append($(li)); | ||
| 422 | } | ||
| 423 | |||
| 424 | libtoaster.showChangeNotification(message); | ||
| 425 | } | ||
| 426 | |||
| 427 | /* Show the modal dialog which gives the option to remove layers which | ||
| 428 | * aren't compatible with the proposed release | ||
| 429 | */ | ||
| 430 | function showReleaseLayerChangeModal(release, layers){ | ||
| 431 | var layersToRmList = releaseModal.find("#layers-to-remove-list"); | ||
| 432 | layersToRmList.text(""); | ||
| 433 | |||
| 434 | releaseModal.find(".proposed-release-change-name").text(release.description); | ||
| 435 | releaseModal.data("layers", layers); | ||
| 436 | releaseModal.data("release", release); | ||
| 437 | |||
| 438 | for (var i in layers){ | ||
| 439 | layersToRmList.append($("<li></li>").text(layers[i].name)); | ||
| 440 | } | ||
| 441 | releaseModal.modal('show'); | ||
| 442 | } | ||
| 443 | |||
| 444 | $("#change-release-btn").click(function(e){ | ||
| 445 | e.preventDefault(); | ||
| 446 | |||
| 447 | var newRelease = releaseForm.find("option:selected").data('release'); | ||
| 448 | |||
| 449 | $.getJSON(ctx.testReleaseChangeUrl, | ||
| 450 | { new_release_id: newRelease.id }, | ||
| 451 | function(layers) { | ||
| 452 | if (layers.rows.length === 0){ | ||
| 453 | /* No layers to change for this release */ | ||
| 454 | changeProjectRelease(newRelease, []); | ||
| 455 | } else { | ||
| 456 | showReleaseLayerChangeModal(newRelease, layers.rows); | ||
| 457 | } | ||
| 458 | }); | ||
| 459 | }); | ||
| 460 | |||
| 461 | /* Release change modal accept */ | ||
| 462 | $("#change-release-and-rm-layers").click(function(){ | ||
| 463 | var layers = releaseModal.data("layers"); | ||
| 464 | var release = releaseModal.data("release"); | ||
| 465 | |||
| 466 | changeProjectRelease(release, layers); | ||
| 467 | }); | 332 | }); |
| 468 | 333 | ||
| 469 | } | 334 | } |
diff --git a/bitbake/lib/toaster/toastergui/static/js/tests/test.js b/bitbake/lib/toaster/toastergui/static/js/tests/test.js index f8d566b3e3..d7953de447 100644 --- a/bitbake/lib/toaster/toastergui/static/js/tests/test.js +++ b/bitbake/lib/toaster/toastergui/static/js/tests/test.js | |||
| @@ -42,9 +42,8 @@ QUnit.test("Layer alert notification", function(assert) { | |||
| 42 | 42 | ||
| 43 | QUnit.test("Project info", function(assert){ | 43 | QUnit.test("Project info", function(assert){ |
| 44 | var done = assert.async(); | 44 | var done = assert.async(); |
| 45 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ | 45 | libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl, function(prjInfo){ |
| 46 | assert.ok(prjInfo.machine.name); | 46 | assert.ok(prjInfo.machine.name); |
| 47 | assert.ok(prjInfo.releases.length > 0); | ||
| 48 | assert.ok(prjInfo.layers.length > 0); | 47 | assert.ok(prjInfo.layers.length > 0); |
| 49 | assert.ok(prjInfo.freqtargets); | 48 | assert.ok(prjInfo.freqtargets); |
| 50 | assert.ok(prjInfo.release); | 49 | assert.ok(prjInfo.release); |
| @@ -82,11 +81,11 @@ QUnit.test("Add layer", function(assert){ | |||
| 82 | }, 200); | 81 | }, 200); |
| 83 | 82 | ||
| 84 | /* Compare the number of layers before and after the add in the project */ | 83 | /* Compare the number of layers before and after the add in the project */ |
| 85 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ | 84 | libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl, function(prjInfo){ |
| 86 | var origNumLayers = prjInfo.layers.length; | 85 | var origNumLayers = prjInfo.layers.length; |
| 87 | 86 | ||
| 88 | libtoaster.addRmLayer(layer, true, function(deps){ | 87 | libtoaster.addRmLayer(layer, true, function(deps){ |
| 89 | libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, | 88 | libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl, |
| 90 | function(prjInfo){ | 89 | function(prjInfo){ |
| 91 | assert.ok(prjInfo.layers.length > origNumLayers, | 90 | assert.ok(prjInfo.layers.length > origNumLayers, |
| 92 | "Layer not added to project"); | 91 | "Layer not added to project"); |
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html index 58491eba81..c1b1417a76 100644 --- a/bitbake/lib/toaster/toastergui/templates/base.html +++ b/bitbake/lib/toaster/toastergui/templates/base.html | |||
| @@ -44,6 +44,7 @@ | |||
| 44 | {% if project.id %} | 44 | {% if project.id %} |
| 45 | projectId : {{project.id}}, | 45 | projectId : {{project.id}}, |
| 46 | projectPageUrl : {% url 'project' project.id as purl %}{{purl|json}}, | 46 | projectPageUrl : {% url 'project' project.id as purl %}{{purl|json}}, |
| 47 | xhrProjectUrl : {% url 'xhr_project' project.id as pxurl %}{{pxurl|json}}, | ||
| 47 | projectName : {{project.name|json}}, | 48 | projectName : {{project.name|json}}, |
| 48 | recipesTypeAheadUrl: {% url 'xhr_recipestypeahead' project.id as paturl%}{{paturl|json}}, | 49 | recipesTypeAheadUrl: {% url 'xhr_recipestypeahead' project.id as paturl%}{{paturl|json}}, |
| 49 | layersTypeAheadUrl: {% url 'xhr_layerstypeahead' project.id as paturl%}{{paturl|json}}, | 50 | layersTypeAheadUrl: {% url 'xhr_layerstypeahead' project.id as paturl%}{{paturl|json}}, |
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 9509cd5928..1232611e2e 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
| @@ -220,6 +220,10 @@ urlpatterns = patterns('toastergui.views', | |||
| 220 | api.XhrBuildRequest.as_view(), | 220 | api.XhrBuildRequest.as_view(), |
| 221 | name='xhr_buildrequest'), | 221 | name='xhr_buildrequest'), |
| 222 | 222 | ||
| 223 | url(r'xhr_project/(?P<project_id>\d+)$', | ||
| 224 | api.XhrProject.as_view(), | ||
| 225 | name='xhr_project'), | ||
| 226 | |||
| 223 | url(r'^mostrecentbuilds$', api.MostRecentBuildsView.as_view(), | 227 | url(r'^mostrecentbuilds$', api.MostRecentBuildsView.as_view(), |
| 224 | name='most_recent_builds'), | 228 | name='most_recent_builds'), |
| 225 | 229 | ||
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 365a1e88ff..2efb0fd56c 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -1361,136 +1361,11 @@ if True: | |||
| 1361 | 1361 | ||
| 1362 | raise Exception("Invalid HTTP method for this page") | 1362 | raise Exception("Invalid HTTP method for this page") |
| 1363 | 1363 | ||
| 1364 | |||
| 1365 | |||
| 1366 | # Shows the edit project page | 1364 | # Shows the edit project page |
| 1367 | @_template_renderer('project.html') | ||
| 1368 | def project(request, pid): | 1365 | def project(request, pid): |
| 1369 | prj = Project.objects.get(id = pid) | 1366 | project = Project.objects.get(pk=pid) |
| 1370 | 1367 | context = {"project": project} | |
| 1371 | try: | 1368 | return render(request, "project.html", context) |
| 1372 | puser = User.objects.get(id = prj.user_id) | ||
| 1373 | except User.DoesNotExist: | ||
| 1374 | puser = None | ||
| 1375 | |||
| 1376 | # execute POST requests | ||
| 1377 | if request.method == "POST": | ||
| 1378 | # add layers | ||
| 1379 | if 'layerAdd' in request.POST and len(request.POST['layerAdd']) > 0: | ||
| 1380 | for lc in Layer_Version.objects.filter(pk__in=[i for i in request.POST['layerAdd'].split(",") if len(i) > 0]): | ||
| 1381 | ProjectLayer.objects.get_or_create(project = prj, layercommit = lc) | ||
| 1382 | |||
| 1383 | # remove layers | ||
| 1384 | if 'layerDel' in request.POST and len(request.POST['layerDel']) > 0: | ||
| 1385 | for t in request.POST['layerDel'].strip().split(" "): | ||
| 1386 | pt = ProjectLayer.objects.filter(project = prj, layercommit_id = int(t)).delete() | ||
| 1387 | |||
| 1388 | if 'projectName' in request.POST: | ||
| 1389 | prj.name = request.POST['projectName'] | ||
| 1390 | prj.save(); | ||
| 1391 | |||
| 1392 | if 'projectVersion' in request.POST: | ||
| 1393 | # If the release is the current project then return now | ||
| 1394 | if prj.release.pk == int(request.POST.get('projectVersion',-1)): | ||
| 1395 | return {} | ||
| 1396 | |||
| 1397 | prj.release = Release.objects.get(pk = request.POST['projectVersion']) | ||
| 1398 | # we need to change the bitbake version | ||
| 1399 | prj.bitbake_version = prj.release.bitbake_version | ||
| 1400 | prj.save() | ||
| 1401 | # we need to change the layers | ||
| 1402 | for project in prj.projectlayer_set.all(): | ||
| 1403 | # find and add a similarly-named layer on the new branch | ||
| 1404 | try: | ||
| 1405 | layer_versions = prj.get_all_compatible_layer_versions() | ||
| 1406 | layer_versions = layer_versions.filter(layer__name = project.layercommit.layer.name) | ||
| 1407 | ProjectLayer.objects.get_or_create(project = prj, layercommit = layer_versions.first()) | ||
| 1408 | except IndexError: | ||
| 1409 | pass | ||
| 1410 | finally: | ||
| 1411 | # get rid of the old entry | ||
| 1412 | project.delete() | ||
| 1413 | |||
| 1414 | if 'machineName' in request.POST: | ||
| 1415 | machinevar = prj.projectvariable_set.get(name="MACHINE") | ||
| 1416 | machinevar.value=request.POST['machineName'] | ||
| 1417 | machinevar.save() | ||
| 1418 | |||
| 1419 | |||
| 1420 | # we use implicit knowledge of the current user's project to filter layer information, e.g. | ||
| 1421 | pid = prj.id | ||
| 1422 | |||
| 1423 | from collections import Counter | ||
| 1424 | |||
| 1425 | freqtargets = Counter(Target.objects.filter( | ||
| 1426 | Q(build__project=prj), | ||
| 1427 | ~Q(build__outcome=Build.IN_PROGRESS) | ||
| 1428 | ).order_by("target").values_list("target", flat=True)) | ||
| 1429 | |||
| 1430 | freqtargets = freqtargets.most_common(5) | ||
| 1431 | |||
| 1432 | # We now have the targets in order of frequency but if there are two | ||
| 1433 | # with the same frequency then we need to make sure those are in | ||
| 1434 | # alphabetical order without losing the frequency ordering | ||
| 1435 | |||
| 1436 | tmp = [] | ||
| 1437 | switch = None | ||
| 1438 | for i, freqtartget in enumerate(freqtargets): | ||
| 1439 | target, count = freqtartget | ||
| 1440 | try: | ||
| 1441 | target_next, count_next = freqtargets[i+1] | ||
| 1442 | if count == count_next and target > target_next: | ||
| 1443 | switch = target | ||
| 1444 | continue | ||
| 1445 | except IndexError: | ||
| 1446 | pass | ||
| 1447 | |||
| 1448 | tmp.append(target) | ||
| 1449 | |||
| 1450 | if switch: | ||
| 1451 | tmp.append(switch) | ||
| 1452 | switch = None | ||
| 1453 | |||
| 1454 | freqtargets = tmp | ||
| 1455 | |||
| 1456 | layers = [{"id": x.layercommit.pk, "orderid": x.pk, "name" : x.layercommit.layer.name, | ||
| 1457 | "vcs_url": x.layercommit.layer.vcs_url, "local_source_dir": x.layercommit.layer.local_source_dir, "vcs_reference" : x.layercommit.get_vcs_reference(), | ||
| 1458 | "url": x.layercommit.layer.layer_index_url, "layerdetailurl": x.layercommit.get_detailspage_url(prj.pk), | ||
| 1459 | "branch" : {"name" : x.layercommit.get_vcs_reference(), | ||
| 1460 | "layersource" : x.layercommit.layer_source } | ||
| 1461 | } for x in prj.projectlayer_set.all().order_by("id")] | ||
| 1462 | |||
| 1463 | context = { | ||
| 1464 | "project" : prj, | ||
| 1465 | "lvs_nos" : Layer_Version.objects.all().count(), | ||
| 1466 | "completedbuilds": Build.objects.exclude(outcome = Build.IN_PROGRESS).filter(project_id = pid), | ||
| 1467 | "prj" : {"name": prj.name, }, | ||
| 1468 | "buildrequests" : prj.build_set.filter(outcome=Build.IN_PROGRESS), | ||
| 1469 | "builds" : Build.get_recent(prj), | ||
| 1470 | "layers" : layers, | ||
| 1471 | "targets" : [{"target" : x.target, "task" : x.task, "pk": x.pk} for x in prj.projecttarget_set.all()], | ||
| 1472 | "variables": [(x.name, x.value) for x in prj.projectvariable_set.all()], | ||
| 1473 | "freqtargets": freqtargets, | ||
| 1474 | "releases": [{"id": x.pk, "name": x.name, "description":x.description} for x in Release.objects.all()], | ||
| 1475 | "project_html": 1, | ||
| 1476 | "recipesTypeAheadUrl": reverse('xhr_recipestypeahead', args=(prj.pk,)), | ||
| 1477 | "projectBuildsUrl": reverse('projectbuilds', args=(prj.pk,)), | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | if prj.release is not None: | ||
| 1481 | context['release'] = { "id": prj.release.pk, "name": prj.release.name, "description": prj.release.description} | ||
| 1482 | |||
| 1483 | |||
| 1484 | try: | ||
| 1485 | context["machine"] = {"name": prj.projectvariable_set.get(name="MACHINE").value} | ||
| 1486 | except ProjectVariable.DoesNotExist: | ||
| 1487 | context["machine"] = None | ||
| 1488 | try: | ||
| 1489 | context["distro"] = prj.projectvariable_set.get(name="DISTRO").value | ||
| 1490 | except ProjectVariable.DoesNotExist: | ||
| 1491 | context["distro"] = "-- not set yet" | ||
| 1492 | |||
| 1493 | return context | ||
| 1494 | 1369 | ||
| 1495 | def jsunittests(request): | 1370 | def jsunittests(request): |
| 1496 | """ Provides a page for the js unit tests """ | 1371 | """ Provides a page for the js unit tests """ |
