diff options
10 files changed, 119 insertions, 76 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/base.js b/bitbake/lib/toaster/toastergui/static/js/base.js index ccc23e0e60..9424b6c328 100644 --- a/bitbake/lib/toaster/toastergui/static/js/base.js +++ b/bitbake/lib/toaster/toastergui/static/js/base.js | |||
| @@ -15,20 +15,21 @@ function basePageInit (ctx) { | |||
| 15 | 15 | ||
| 16 | /* Hide the change project icon when there is only one project */ | 16 | /* Hide the change project icon when there is only one project */ |
| 17 | if (ctx.numProjects == 1){ | 17 | if (ctx.numProjects == 1){ |
| 18 | $('#project .icon-pencil').hide(); | 18 | $('#project .icon-pencil').hide(); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | newBuildButton.show().removeAttr("disabled"); | 21 | newBuildButton.show().removeAttr("disabled"); |
| 22 | 22 | ||
| 23 | |||
| 23 | _checkProjectBuildable() | 24 | _checkProjectBuildable() |
| 24 | _setupNewBuildButton(); | 25 | _setupNewBuildButton(); |
| 25 | 26 | ||
| 26 | 27 | ||
| 27 | function _checkProjectBuildable(){ | 28 | function _checkProjectBuildable(){ |
| 28 | if (currentProjectId == undefined) | 29 | if (libtoaster.ctx.projectId == undefined) |
| 29 | return; | 30 | return; |
| 30 | 31 | ||
| 31 | libtoaster.getProjectInfo(ctx.projectInfoUrl, currentProjectId, | 32 | libtoaster.getProjectInfo(ctx.projectInfoUrl, libtoaster.ctx.projectId, |
| 32 | function(data){ | 33 | function(data){ |
| 33 | if (data.machine.name == undefined || data.layers.length == 0) { | 34 | if (data.machine.name == undefined || data.layers.length == 0) { |
| 34 | /* we can't build anything with out a machine and some layers */ | 35 | /* we can't build anything with out a machine and some layers */ |
| @@ -53,18 +54,13 @@ function basePageInit (ctx) { | |||
| 53 | /* If we don't have a current project then present the set project | 54 | /* If we don't have a current project then present the set project |
| 54 | * form. | 55 | * form. |
| 55 | */ | 56 | */ |
| 56 | if (currentProjectId == undefined) { | 57 | if (libtoaster.ctx.projectId == undefined) { |
| 57 | $('#change-project-form').show(); | 58 | $('#change-project-form').show(); |
| 58 | $('#project .icon-pencil').hide(); | 59 | $('#project .icon-pencil').hide(); |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | libtoaster.makeTypeahead(newBuildTargetInput, { type : "targets", project_id: currentProjectId }, function(item){ | ||
| 62 | /* successfully selected a target */ | ||
| 63 | selectedTarget = item; | ||
| 64 | }); | ||
| 65 | 62 | ||
| 66 | 63 | libtoaster.makeTypeahead(newBuildProjectInput, libtoaster.ctx.projectsUrl, { format : "json" }, function(item){ | |
| 67 | libtoaster.makeTypeahead(newBuildProjectInput, { type : "projects" }, function(item){ | ||
| 68 | /* successfully selected a project */ | 64 | /* successfully selected a project */ |
| 69 | newBuildProjectSaveBtn.removeAttr("disabled"); | 65 | newBuildProjectSaveBtn.removeAttr("disabled"); |
| 70 | selectedProject = item; | 66 | selectedProject = item; |
| @@ -93,20 +89,40 @@ function basePageInit (ctx) { | |||
| 93 | if (!selectedTarget) | 89 | if (!selectedTarget) |
| 94 | selectedTarget = { name: newBuildTargetInput.val() }; | 90 | selectedTarget = { name: newBuildTargetInput.val() }; |
| 95 | /* fire and forget */ | 91 | /* fire and forget */ |
| 96 | libtoaster.startABuild(ctx.projectBuildUrl, currentProjectId, selectedTarget.name, null, null); | 92 | libtoaster.startABuild(ctx.projectBuildUrl, libtoaster.ctx.projectId, selectedTarget.name, null, null); |
| 97 | window.location.replace(ctx.projectBasePageUrl+currentProjectId); | 93 | window.location.replace(libtoaster.ctx.projectPageUrl); |
| 98 | }); | 94 | }); |
| 99 | 95 | ||
| 100 | newBuildProjectSaveBtn.click(function() { | 96 | newBuildProjectSaveBtn.click(function() { |
| 101 | currentProjectId = selectedProject.id | 97 | libtoaster.ctx.projectId = selectedProject.pk |
| 102 | /* Update the typeahead project_id paramater */ | 98 | /* Update the typeahead project_id paramater */ |
| 103 | _checkProjectBuildable(); | 99 | _checkProjectBuildable(); |
| 104 | newBuildTargetInput.data('typeahead').options.xhrParams.project_id = currentProjectId; | ||
| 105 | newBuildTargetInput.val(""); | ||
| 106 | 100 | ||
| 107 | $("#new-build-button #project a").text(selectedProject.name).attr('href', ctx.projectBasePageUrl+currentProjectId); | 101 | /* we set the effective context of the page to the currently selected project */ |
| 108 | $("#new-build-button .alert a").attr('href', ctx.projectBasePageUrl+currentProjectId); | 102 | /* TBD: do we override even if we already have a context project ?? */ |
| 103 | /* TODO: replace global library context with references to the "selected" project */ | ||
| 104 | libtoaster.ctx.projectPageUrl = selectedProject.projectPageUrl; | ||
| 105 | libtoaster.ctx.xhrProjectEditUrl = selectedProject.xhrProjectEditUrl; | ||
| 106 | libtoaster.ctx.projectName = selectedProject.name; | ||
| 107 | libtoaster.ctx.projectId = selectedProject.id; | ||
| 108 | |||
| 109 | ctx.projectBuildUrl = selectedProject.projectBuildUrl; | ||
| 110 | |||
| 111 | /* we can create a target typeahead only after we have a project selected */ | ||
| 112 | newBuildTargetInput.prop("disabled", false); | ||
| 113 | newBuildTargetBuildBtn.prop("disabled", false); | ||
| 114 | |||
| 115 | libtoaster.makeTypeahead(newBuildTargetInput, selectedProject.xhrProjectDataTypeaheadUrl, { type : "targets" }, function(item){ | ||
| 116 | /* successfully selected a target */ | ||
| 117 | selectedTarget = item; | ||
| 118 | }); | ||
| 119 | |||
| 120 | newBuildTargetInput.val(""); | ||
| 109 | 121 | ||
| 122 | /* set up new form aspect */ | ||
| 123 | $("#new-build-button #project a").text(selectedProject.name).attr('href', libtoaster.ctx.projectPageUrl); | ||
| 124 | $("#new-build-button .alert a").attr('href', libtoaster.ctx.projectPageUrl); | ||
| 125 | $("#project .icon-pencil").show(); | ||
| 110 | 126 | ||
| 111 | $("#change-project-form").slideUp({ 'complete' : function() { | 127 | $("#change-project-form").slideUp({ 'complete' : function() { |
| 112 | $("#new-build-button #project").show(); | 128 | $("#new-build-button #project").show(); |
| @@ -116,6 +132,7 @@ function basePageInit (ctx) { | |||
| 116 | $('#new-build-button #project .icon-pencil').click(function() { | 132 | $('#new-build-button #project .icon-pencil').click(function() { |
| 117 | newBuildProjectSaveBtn.attr("disabled", "disabled"); | 133 | newBuildProjectSaveBtn.attr("disabled", "disabled"); |
| 118 | newBuildProjectInput.val($("#new-build-button #project a").text()); | 134 | newBuildProjectInput.val($("#new-build-button #project a").text()); |
| 135 | $("#cancel-change-project").show(); | ||
| 119 | $(this).parent().hide(); | 136 | $(this).parent().hide(); |
| 120 | $("#change-project-form").slideDown(); | 137 | $("#change-project-form").slideDown(); |
| 121 | }); | 138 | }); |
diff --git a/bitbake/lib/toaster/toastergui/static/js/importlayer.js b/bitbake/lib/toaster/toastergui/static/js/importlayer.js index 875cc342b8..beb2ede3dc 100644 --- a/bitbake/lib/toaster/toastergui/static/js/importlayer.js +++ b/bitbake/lib/toaster/toastergui/static/js/importlayer.js | |||
| @@ -18,7 +18,7 @@ function importLayerPageInit (ctx) { | |||
| 18 | 18 | ||
| 19 | $("#new-project-button").hide(); | 19 | $("#new-project-button").hide(); |
| 20 | 20 | ||
| 21 | libtoaster.makeTypeahead(layerDepInput, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ | 21 | libtoaster.makeTypeahead(layerDepInput, libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ |
| 22 | currentLayerDepSelection = item; | 22 | currentLayerDepSelection = item; |
| 23 | 23 | ||
| 24 | layerDepBtn.removeAttr("disabled"); | 24 | layerDepBtn.removeAttr("disabled"); |
| @@ -28,7 +28,7 @@ function importLayerPageInit (ctx) { | |||
| 28 | /* We automatically add "openembedded-core" layer for convenience as a | 28 | /* We automatically add "openembedded-core" layer for convenience as a |
| 29 | * dependency as pretty much all layers depend on this one | 29 | * dependency as pretty much all layers depend on this one |
| 30 | */ | 30 | */ |
| 31 | $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: "openembedded-core" }, function(layer) { | 31 | $.getJSON(libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: "openembedded-core" }, function(layer) { |
| 32 | if (layer.list.length == 1) { | 32 | if (layer.list.length == 1) { |
| 33 | currentLayerDepSelection = layer.list[0]; | 33 | currentLayerDepSelection = layer.list[0]; |
| 34 | layerDepBtn.click(); | 34 | layerDepBtn.click(); |
| @@ -211,7 +211,7 @@ function importLayerPageInit (ctx) { | |||
| 211 | var name = $(this).val(); | 211 | var name = $(this).val(); |
| 212 | 212 | ||
| 213 | /* Check if the layer name exists */ | 213 | /* Check if the layer name exists */ |
| 214 | $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: name }, function(layer) { | 214 | $.getJSON(libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: name }, function(layer) { |
| 215 | if (layer.list.length > 0) { | 215 | if (layer.list.length > 0) { |
| 216 | for (var i in layer.list){ | 216 | for (var i in layer.list){ |
| 217 | if (layer.list[i].name == name) { | 217 | if (layer.list[i].name == name) { |
diff --git a/bitbake/lib/toaster/toastergui/static/js/layerdetails.js b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js index 3746ea26e3..8e14b8f277 100644 --- a/bitbake/lib/toaster/toastergui/static/js/layerdetails.js +++ b/bitbake/lib/toaster/toastergui/static/js/layerdetails.js | |||
| @@ -9,7 +9,7 @@ function layerDetailsPageInit (ctx) { | |||
| 9 | var addRmLayerBtn = $("#add-remove-layer-btn"); | 9 | var addRmLayerBtn = $("#add-remove-layer-btn"); |
| 10 | 10 | ||
| 11 | /* setup the dependencies typeahead */ | 11 | /* setup the dependencies typeahead */ |
| 12 | libtoaster.makeTypeahead(layerDepInput, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ | 12 | libtoaster.makeTypeahead(layerDepInput, libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ |
| 13 | currentLayerDepSelection = item; | 13 | currentLayerDepSelection = item; |
| 14 | 14 | ||
| 15 | layerDepBtn.removeAttr("disabled"); | 15 | layerDepBtn.removeAttr("disabled"); |
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js index 99e1f03095..72fb0a93f5 100644 --- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js +++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js | |||
| @@ -10,16 +10,16 @@ var libtoaster = (function (){ | |||
| 10 | * xhrUrl: the url to get the JSON from expects JSON in the form: | 10 | * xhrUrl: the url to get the JSON from expects JSON in the form: |
| 11 | * { "list": [ { "name": "test", "detail" : "a test thing" }, .... ] } | 11 | * { "list": [ { "name": "test", "detail" : "a test thing" }, .... ] } |
| 12 | * xhrParams: the data/parameters to pass to the getJSON url e.g. | 12 | * xhrParams: the data/parameters to pass to the getJSON url e.g. |
| 13 | * { 'type' : 'projects' } the text typed will be passed as 'value'. | 13 | * { 'type' : 'projects' } the text typed will be passed as 'search'. |
| 14 | * selectedCB: function to call once an item has been selected one | 14 | * selectedCB: function to call once an item has been selected one |
| 15 | * arg of the item. | 15 | * arg of the item. |
| 16 | */ | 16 | */ |
| 17 | function _makeTypeahead (jQElement, xhrParams, selectedCB) { | 17 | function _makeTypeahead (jQElement, xhrUrl, xhrParams, selectedCB) { |
| 18 | 18 | ||
| 19 | jQElement.typeahead({ | 19 | jQElement.typeahead({ |
| 20 | source: function(query, process){ | 20 | source: function(query, process){ |
| 21 | xhrParams.value = query; | 21 | xhrParams.search = query; |
| 22 | $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, this.options.xhrParams, function(data){ | 22 | $.getJSON(xhrUrl, this.options.xhrParams, function(data){ |
| 23 | if (data.error !== "ok") { | 23 | if (data.error !== "ok") { |
| 24 | console.log("Error getting data from server "+data.error); | 24 | console.log("Error getting data from server "+data.error); |
| 25 | return; | 25 | return; |
| @@ -41,7 +41,7 @@ var libtoaster = (function (){ | |||
| 41 | return $('<span></span>').text(item.name).get(0); | 41 | return $('<span></span>').text(item.name).get(0); |
| 42 | }, | 42 | }, |
| 43 | sorter: function (items) { return items; }, | 43 | sorter: function (items) { return items; }, |
| 44 | xhrUrl: libtoaster.ctx.xhrDataTypeaheadUrl, | 44 | xhrUrl: xhrUrl, |
| 45 | xhrParams: xhrParams, | 45 | xhrParams: xhrParams, |
| 46 | }); | 46 | }); |
| 47 | 47 | ||
| @@ -172,7 +172,7 @@ var libtoaster = (function (){ | |||
| 172 | 172 | ||
| 173 | function _getLayerDepsForProject(projectId, layerId, onSuccess, onFail){ | 173 | function _getLayerDepsForProject(projectId, layerId, onSuccess, onFail){ |
| 174 | /* Check for dependencies not in the current project */ | 174 | /* Check for dependencies not in the current project */ |
| 175 | $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, | 175 | $.getJSON(libtoaster.ctx.xhrProjectDataTypeaheadUrl, |
| 176 | { type: 'layerdeps', 'value': layerId , project_id: projectId }, | 176 | { type: 'layerdeps', 'value': layerId , project_id: projectId }, |
| 177 | function(data) { | 177 | function(data) { |
| 178 | if (data.error != "ok") { | 178 | if (data.error != "ok") { |
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html index 230dee49d6..e10dc11673 100644 --- a/bitbake/lib/toaster/toastergui/templates/base.html +++ b/bitbake/lib/toaster/toastergui/templates/base.html | |||
| @@ -31,11 +31,19 @@ | |||
| 31 | projectId : {{project.id|default:'undefined'}}, | 31 | projectId : {{project.id|default:'undefined'}}, |
| 32 | jsUrl : "{% static 'js/' %}", | 32 | jsUrl : "{% static 'js/' %}", |
| 33 | htmlUrl : "{% static 'html/' %}", | 33 | htmlUrl : "{% static 'html/' %}", |
| 34 | projectsUrl : "{% url 'all-projects' %}", | ||
| 34 | {% if project.id %} | 35 | {% if project.id %} |
| 35 | xhrDataTypeaheadUrl : "{% url 'xhr_datatypeahead' project.id %}", | 36 | xhrProjectDataTypeaheadUrl : "{% url 'xhr_datatypeahead' project.id %}", |
| 36 | xhrProjectEditUrl : "{% url 'xhr_projectedit' project.id %}", | 37 | xhrProjectEditUrl : "{% url 'xhr_projectedit' project.id %}", |
| 37 | projectPageUrl : "{% url 'project' project.id %}", | 38 | projectPageUrl : "{% url 'project' project.id %}", |
| 38 | projectName : "{{project.name}}", | 39 | projectName : "{{project.name}}", |
| 40 | projectId : {{project.id}}, | ||
| 41 | {% else %} | ||
| 42 | xhrProjectDataTypeaheadUrl : undefined, | ||
| 43 | xhrProjectEditUrl : undefined, | ||
| 44 | projectPageUrl : undefined, | ||
| 45 | projectName : undefined, | ||
| 46 | projectId : undefined, | ||
| 39 | {% endif %} | 47 | {% endif %} |
| 40 | }; | 48 | }; |
| 41 | </script> | 49 | </script> |
| @@ -45,8 +53,6 @@ | |||
| 45 | $(document).ready(function () { | 53 | $(document).ready(function () { |
| 46 | /* Vars needed for base.js */ | 54 | /* Vars needed for base.js */ |
| 47 | var ctx = {}; | 55 | var ctx = {}; |
| 48 | ctx.projectBuildUrl = "{% url 'xhr_build' %}"; | ||
| 49 | ctx.projectBasePageUrl = "{% url 'base_project' %}"; | ||
| 50 | ctx.projectInfoUrl = "{% url 'xhr_projectinfo' %}"; | 56 | ctx.projectInfoUrl = "{% url 'xhr_projectinfo' %}"; |
| 51 | ctx.numProjects = {{projects|length}}; | 57 | ctx.numProjects = {{projects|length}}; |
| 52 | ctx.currentUrl = "{{request.path|escapejs}}"; | 58 | ctx.currentUrl = "{{request.path|escapejs}}"; |
| @@ -99,7 +105,7 @@ | |||
| 99 | <div class="input-append"> | 105 | <div class="input-append"> |
| 100 | <input type="text" class="input-medium" id="project-name-input" placeholder="Type a project name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead"/> | 106 | <input type="text" class="input-medium" id="project-name-input" placeholder="Type a project name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead"/> |
| 101 | <button id="save-project-button" class="btn" type="button">Save</button> | 107 | <button id="save-project-button" class="btn" type="button">Save</button> |
| 102 | <a href="#" id="cancel-change-project" class="btn btn-link">Cancel</a> | 108 | <a href="#" id="cancel-change-project" class="btn btn-link" style="display: none">Cancel</a> |
| 103 | </div> | 109 | </div> |
| 104 | <p><a id="view-all-projects" href="{% url 'all-projects' %}">View all projects</a></p> | 110 | <p><a id="view-all-projects" href="{% url 'all-projects' %}">View all projects</a></p> |
| 105 | </form> | 111 | </form> |
| @@ -111,9 +117,9 @@ | |||
| 111 | <li id="targets-form"> | 117 | <li id="targets-form"> |
| 112 | <h6>Recipe(s):</h6> | 118 | <h6>Recipe(s):</h6> |
| 113 | <form> | 119 | <form> |
| 114 | <input type="text" class="input-xlarge" id="build-target-input" placeholder="Type a recipe name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead" /> | 120 | <input type="text" class="input-xlarge" id="build-target-input" placeholder="Type a recipe name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead" disabled/> |
| 115 | <div> | 121 | <div> |
| 116 | <a class="btn btn-primary" id="build-button" data-project-id="{{project.id}}">Build</a> | 122 | <button class="btn btn-primary" id="build-button" data-project-id="{{project.id}}" disabled>Build</button> |
| 117 | </div> | 123 | </div> |
| 118 | </form> | 124 | </form> |
| 119 | </li> | 125 | </li> |
diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html index 4c28cae810..ce023f51af 100644 --- a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html +++ b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html | |||
| @@ -57,7 +57,7 @@ | |||
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | // load cookie for number of entries to be displayed on page | 60 | // load data for number of entries to be displayed on page |
| 61 | if ({{request.GET.count}} != "") { | 61 | if ({{request.GET.count}} != "") { |
| 62 | pagesize = {{request.GET.count}}; | 62 | pagesize = {{request.GET.count}}; |
| 63 | } | 63 | } |
diff --git a/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html b/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html index 434facba93..f40c21d99f 100644 --- a/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html +++ b/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | <!-- Update page display settings --> | 38 | <!-- Update page display settings --> |
| 39 | <script> | 39 | <script> |
| 40 | $(document).ready(function() { | 40 | $(document).ready(function() { |
| 41 | // load cookie for number of entries to be displayed on page | 41 | // load data for number of entries to be displayed on page |
| 42 | if ({{request.GET.count}} != "") { | 42 | if ({{request.GET.count}} != "") { |
| 43 | pagesize = {{request.GET.count}}; | 43 | pagesize = {{request.GET.count}}; |
| 44 | } | 44 | } |
diff --git a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py index 8028ae0022..e79a4e5848 100644 --- a/bitbake/lib/toaster/toastergui/templatetags/projecttags.py +++ b/bitbake/lib/toaster/toastergui/templatetags/projecttags.py | |||
| @@ -51,11 +51,11 @@ def get_tasks(queryset): | |||
| 51 | 51 | ||
| 52 | 52 | ||
| 53 | @register.filter(name = "json") | 53 | @register.filter(name = "json") |
| 54 | def json(value): | 54 | def json(value, default = None): |
| 55 | # JSON spec says that "\/" is functionally identical to "/" to allow for HTML-tag embedding in JSON strings | 55 | # JSON spec says that "\/" is functionally identical to "/" to allow for HTML-tag embedding in JSON strings |
| 56 | # unfortunately, I can't find any option in the json module to turn on forward-slash escaping, so we do | 56 | # unfortunately, I can't find any option in the json module to turn on forward-slash escaping, so we do |
| 57 | # it manually here | 57 | # it manually here |
| 58 | return mark_safe(JsonLib.dumps(value, ensure_ascii=False).replace('</', '<\\/')) | 58 | return mark_safe(JsonLib.dumps(value, default = default, ensure_ascii=False).replace('</', '<\\/')) |
| 59 | 59 | ||
| 60 | @register.assignment_tag | 60 | @register.assignment_tag |
| 61 | def query(qs, **kwargs): | 61 | def query(qs, **kwargs): |
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 7a1132febc..4e328dae17 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
| @@ -77,8 +77,6 @@ urlpatterns = patterns('toastergui.views', | |||
| 77 | 77 | ||
| 78 | url(r'^projects/$', 'projects', name='all-projects'), | 78 | url(r'^projects/$', 'projects', name='all-projects'), |
| 79 | 79 | ||
| 80 | url(r'^project/$', lambda x: HttpResponseBadRequest(), name='base_project'), | ||
| 81 | |||
| 82 | url(r'^project/(?P<pid>\d+)/$', 'project', name='project'), | 80 | url(r'^project/(?P<pid>\d+)/$', 'project', name='project'), |
| 83 | url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'), | 81 | url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'), |
| 84 | url(r'^project/(?P<pid>\d+)/builds/$', 'projectbuilds', name='projectbuilds'), | 82 | url(r'^project/(?P<pid>\d+)/builds/$', 'projectbuilds', name='projectbuilds'), |
| @@ -110,7 +108,6 @@ urlpatterns = patterns('toastergui.views', | |||
| 110 | name="all-layers"), | 108 | name="all-layers"), |
| 111 | 109 | ||
| 112 | 110 | ||
| 113 | url(r'^xhr_build/$', 'xhr_build', name='xhr_build'), | ||
| 114 | url(r'^xhr_projectbuild/(?P<pid>\d+)$', 'xhr_projectbuild', name='xhr_projectbuild'), | 111 | url(r'^xhr_projectbuild/(?P<pid>\d+)$', 'xhr_projectbuild', name='xhr_projectbuild'), |
| 115 | url(r'^xhr_projectinfo/$', 'xhr_projectinfo', name='xhr_projectinfo'), | 112 | url(r'^xhr_projectinfo/$', 'xhr_projectinfo', name='xhr_projectinfo'), |
| 116 | url(r'^xhr_projectedit/(?P<pid>\d+)$', 'xhr_projectedit', name='xhr_projectedit'), | 113 | url(r'^xhr_projectedit/(?P<pid>\d+)$', 'xhr_projectedit', name='xhr_projectedit'), |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 0e248a7435..d4a9b4ca0d 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -129,7 +129,19 @@ def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs): | |||
| 129 | if not i in params: | 129 | if not i in params: |
| 130 | params[i] = urllib.unquote(str(mandatory_parameters[i])) | 130 | params[i] = urllib.unquote(str(mandatory_parameters[i])) |
| 131 | 131 | ||
| 132 | return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs) | 132 | return redirect(url + "?%s" % urllib.urlencode(params), permanent = False, *args, **kwargs) |
| 133 | |||
| 134 | class RedirectException(Exception): | ||
| 135 | def __init__(self, view, g, mandatory_parameters, *args, **kwargs): | ||
| 136 | super(RedirectException, self).__init__() | ||
| 137 | self.view = view | ||
| 138 | self.g = g | ||
| 139 | self.mandatory_parameters = mandatory_parameters | ||
| 140 | self.oargs = args | ||
| 141 | self.okwargs = kwargs | ||
| 142 | |||
| 143 | def get_redirect_response(self): | ||
| 144 | return _redirect_parameters(self.view, self.g, self.mandatory_parameters, self.oargs, self.okwargs) | ||
| 133 | 145 | ||
| 134 | FIELD_SEPARATOR = ":" | 146 | FIELD_SEPARATOR = ":" |
| 135 | AND_VALUE_SEPARATOR = "!" | 147 | AND_VALUE_SEPARATOR = "!" |
| @@ -2200,14 +2212,6 @@ if toastermain.settings.MANAGED: | |||
| 2200 | response['Pragma'] = "no-cache" | 2212 | response['Pragma'] = "no-cache" |
| 2201 | return response | 2213 | return response |
| 2202 | 2214 | ||
| 2203 | # This is a wrapper for xhr_projectbuild which allows for a project id | ||
| 2204 | # which only becomes known client side. | ||
| 2205 | def xhr_build(request): | ||
| 2206 | if request.POST.has_key("project_id"): | ||
| 2207 | pid = request.POST['project_id'] | ||
| 2208 | return xhr_projectbuild(request, pid) | ||
| 2209 | else: | ||
| 2210 | raise BadParameterException("invalid project id") | ||
| 2211 | 2215 | ||
| 2212 | def xhr_projectbuild(request, pid): | 2216 | def xhr_projectbuild(request, pid): |
| 2213 | try: | 2217 | try: |
| @@ -2333,7 +2337,7 @@ if toastermain.settings.MANAGED: | |||
| 2333 | # returns layers for current project release that are not in the project set, matching the name | 2337 | # returns layers for current project release that are not in the project set, matching the name |
| 2334 | if request.GET['type'] == "layers": | 2338 | if request.GET['type'] == "layers": |
| 2335 | # all layers for the current project | 2339 | # all layers for the current project |
| 2336 | queryset_all = prj.compatible_layerversions().filter(layer__name__icontains=request.GET.get('value','')) | 2340 | queryset_all = prj.compatible_layerversions().filter(layer__name__icontains=request.GET.get('search','')) |
| 2337 | 2341 | ||
| 2338 | # but not layers with equivalent layers already in project | 2342 | # but not layers with equivalent layers already in project |
| 2339 | if not request.GET.has_key('include_added'): | 2343 | if not request.GET.has_key('include_added'): |
| @@ -2348,7 +2352,7 @@ if toastermain.settings.MANAGED: | |||
| 2348 | # returns layer dependencies for a layer, excluding current project layers | 2352 | # returns layer dependencies for a layer, excluding current project layers |
| 2349 | if request.GET['type'] == "layerdeps": | 2353 | if request.GET['type'] == "layerdeps": |
| 2350 | queryset = prj.compatible_layerversions().exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]).filter( | 2354 | queryset = prj.compatible_layerversions().exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]).filter( |
| 2351 | layer__name__in = [ x.depends_on.layer.name for x in LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])]) | 2355 | layer__name__in = [ x.depends_on.layer.name for x in LayerVersionDependency.objects.filter(layer_version_id = request.GET['search'])]) |
| 2352 | 2356 | ||
| 2353 | final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset]) | 2357 | final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset]) |
| 2354 | 2358 | ||
| @@ -2361,7 +2365,7 @@ if toastermain.settings.MANAGED: | |||
| 2361 | 2365 | ||
| 2362 | retval = [] | 2366 | retval = [] |
| 2363 | for i in prj.projectlayer_set.all(): | 2367 | for i in prj.projectlayer_set.all(): |
| 2364 | lv = prj.compatible_layerversions(release = Release.objects.get(pk=request.GET['value'])).filter(layer__name = i.layercommit.layer.name) | 2368 | lv = prj.compatible_layerversions(release = Release.objects.get(pk=request.GET['search'])).filter(layer__name = i.layercommit.layer.name) |
| 2365 | # there is no layer_version with the new release id, and the same name | 2369 | # there is no layer_version with the new release id, and the same name |
| 2366 | if lv.count() < 1: | 2370 | if lv.count() < 1: |
| 2367 | retval.append(i) | 2371 | retval.append(i) |
| @@ -2374,10 +2378,10 @@ if toastermain.settings.MANAGED: | |||
| 2374 | # returns layer versions that provide the named targets | 2378 | # returns layer versions that provide the named targets |
| 2375 | if request.GET['type'] == "layers4target": | 2379 | if request.GET['type'] == "layers4target": |
| 2376 | # we return data only if the recipe can't be provided by the current project layer set | 2380 | # we return data only if the recipe can't be provided by the current project layer set |
| 2377 | if reduce(lambda x, y: x + y, [x.recipe_layer_version.filter(name=request.GET['value']).count() for x in prj.projectlayer_equivalent_set()], 0): | 2381 | if reduce(lambda x, y: x + y, [x.recipe_layer_version.filter(name=request.GET['search']).count() for x in prj.projectlayer_equivalent_set()], 0): |
| 2378 | final_list = [] | 2382 | final_list = [] |
| 2379 | else: | 2383 | else: |
| 2380 | queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET['value']) | 2384 | queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET['search']) |
| 2381 | 2385 | ||
| 2382 | # exclude layers in the project | 2386 | # exclude layers in the project |
| 2383 | queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]) | 2387 | queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]) |
| @@ -2389,7 +2393,7 @@ if toastermain.settings.MANAGED: | |||
| 2389 | 2393 | ||
| 2390 | # returns targets provided by current project layers | 2394 | # returns targets provided by current project layers |
| 2391 | if request.GET['type'] == "targets": | 2395 | if request.GET['type'] == "targets": |
| 2392 | search_token = request.GET.get('value','') | 2396 | search_token = request.GET.get('search','') |
| 2393 | queryset_all = Recipe.objects.filter(layer_version__layer__name__in = [x.layercommit.layer.name for x in prj.projectlayer_set.all().select_related("layercommit__layer")]).filter(Q(name__icontains=search_token) | Q(layer_version__layer__name__icontains=search_token)) | 2397 | queryset_all = Recipe.objects.filter(layer_version__layer__name__in = [x.layercommit.layer.name for x in prj.projectlayer_set.all().select_related("layercommit__layer")]).filter(Q(name__icontains=search_token) | Q(layer_version__layer__name__icontains=search_token)) |
| 2394 | 2398 | ||
| 2395 | # layer_equivalent_set = [] | 2399 | # layer_equivalent_set = [] |
| @@ -2420,7 +2424,7 @@ if toastermain.settings.MANAGED: | |||
| 2420 | if 'project_id' in request.session: | 2424 | if 'project_id' in request.session: |
| 2421 | queryset_all = queryset_all.filter(layer_version__in = prj.projectlayer_equivalent_set()).order_by("name") | 2425 | queryset_all = queryset_all.filter(layer_version__in = prj.projectlayer_equivalent_set()).order_by("name") |
| 2422 | 2426 | ||
| 2423 | search_token = request.GET.get('value','') | 2427 | search_token = request.GET.get('search','') |
| 2424 | queryset_all = queryset_all.filter(Q(name__icontains=search_token) | Q(description__icontains=search_token)) | 2428 | queryset_all = queryset_all.filter(Q(name__icontains=search_token) | Q(description__icontains=search_token)) |
| 2425 | 2429 | ||
| 2426 | return HttpResponse(jsonfilter({ "error":"ok", | 2430 | return HttpResponse(jsonfilter({ "error":"ok", |
| @@ -2432,15 +2436,6 @@ if toastermain.settings.MANAGED: | |||
| 2432 | ) | 2436 | ) |
| 2433 | }), content_type = "application/json") | 2437 | }), content_type = "application/json") |
| 2434 | 2438 | ||
| 2435 | # returns all projects | ||
| 2436 | if request.GET['type'] == "projects": | ||
| 2437 | queryset_all = Project.objects.all() | ||
| 2438 | ret = { "error": "ok", | ||
| 2439 | "list": map (lambda x: {"id":x.pk, "name": x.name}, | ||
| 2440 | queryset_all.filter(name__icontains=request.GET.get('value',''))[:8])} | ||
| 2441 | |||
| 2442 | return HttpResponse(jsonfilter(ret), content_type = "application/json") | ||
| 2443 | |||
| 2444 | raise Exception("Unknown request! " + request.GET.get('type', "No parameter supplied")) | 2439 | raise Exception("Unknown request! " + request.GET.get('type', "No parameter supplied")) |
| 2445 | except Exception as e: | 2440 | except Exception as e: |
| 2446 | return HttpResponse(jsonfilter({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") | 2441 | return HttpResponse(jsonfilter({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") |
| @@ -2866,14 +2861,38 @@ if toastermain.settings.MANAGED: | |||
| 2866 | return build_mru | 2861 | return build_mru |
| 2867 | 2862 | ||
| 2868 | 2863 | ||
| 2869 | def projects(request): | 2864 | def template_renderer(template): |
| 2870 | template="projects.html" | 2865 | def func_wrapper(view): |
| 2866 | def returned_wrapper(request, *args, **kwargs): | ||
| 2867 | try: | ||
| 2868 | context = view(request, *args, **kwargs) | ||
| 2869 | except RedirectException as e: | ||
| 2870 | return e.get_redirect_response() | ||
| 2871 | |||
| 2872 | if request.GET.get('format', None) == 'json': | ||
| 2873 | # objects is a special keyword - it's a Page, but we need the actual objects here | ||
| 2874 | # in XHR, the objects come in the "list" property | ||
| 2875 | if "objects" in context: | ||
| 2876 | context["list"] = context["objects"].object_list | ||
| 2877 | del context["objects"] | ||
| 2878 | |||
| 2879 | # we're about to return; to keep up with the XHR API, we set the error to OK | ||
| 2880 | context["error"] = "ok" | ||
| 2881 | |||
| 2882 | return HttpResponse(jsonfilter(context, default=lambda obj: obj.isoformat() if isinstance(obj, datetime) else obj.__dict__ ), | ||
| 2883 | content_type = "application/json; charset=utf-8") | ||
| 2884 | else: | ||
| 2885 | return render(request, template, context) | ||
| 2886 | return returned_wrapper | ||
| 2887 | return func_wrapper | ||
| 2871 | 2888 | ||
| 2889 | @template_renderer("projects.html") | ||
| 2890 | def projects(request): | ||
| 2872 | (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-') | 2891 | (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-') |
| 2873 | mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } | 2892 | mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } |
| 2874 | retval = _verify_parameters( request.GET, mandatory_parameters ) | 2893 | retval = _verify_parameters( request.GET, mandatory_parameters ) |
| 2875 | if retval: | 2894 | if retval: |
| 2876 | return _redirect_parameters( 'all-projects', request.GET, mandatory_parameters) | 2895 | raise RedirectException( 'all-projects', request.GET, mandatory_parameters ) |
| 2877 | 2896 | ||
| 2878 | queryset_all = Project.objects.all() | 2897 | queryset_all = Project.objects.all() |
| 2879 | 2898 | ||
| @@ -2886,6 +2905,14 @@ if toastermain.settings.MANAGED: | |||
| 2886 | # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display | 2905 | # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display |
| 2887 | project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) | 2906 | project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) |
| 2888 | 2907 | ||
| 2908 | # add fields needed in JSON dumps for API call support | ||
| 2909 | for p in project_info.object_list: | ||
| 2910 | p.id = p.pk | ||
| 2911 | p.xhrProjectDataTypeaheadUrl = reverse('xhr_datatypeahead', args=(p.id,)) | ||
| 2912 | p.projectPageUrl = reverse('project', args=(p.id,)) | ||
| 2913 | p.xhrProjectEditUrl = reverse('xhr_projectedit', args=(p.id,)) | ||
| 2914 | p.projectBuildUrl = reverse('xhr_projectbuild', args=(p.id,)) | ||
| 2915 | |||
| 2889 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) | 2916 | # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) |
| 2890 | build_mru = _managed_get_latest_builds() | 2917 | build_mru = _managed_get_latest_builds() |
| 2891 | 2918 | ||
| @@ -2965,9 +2992,8 @@ if toastermain.settings.MANAGED: | |||
| 2965 | ] | 2992 | ] |
| 2966 | } | 2993 | } |
| 2967 | 2994 | ||
| 2968 | response = render(request, template, context) | ||
| 2969 | _set_parameters_values(pagesize, orderby, request) | 2995 | _set_parameters_values(pagesize, orderby, request) |
| 2970 | return response | 2996 | return context |
| 2971 | 2997 | ||
| 2972 | def buildrequestdetails(request, pid, brid): | 2998 | def buildrequestdetails(request, pid, brid): |
| 2973 | template = "buildrequestdetails.html" | 2999 | template = "buildrequestdetails.html" |
| @@ -3185,9 +3211,6 @@ else: | |||
| 3185 | def xhr_projectbuild(request, pid): | 3211 | def xhr_projectbuild(request, pid): |
| 3186 | return render(request, 'landing_not_managed.html') | 3212 | return render(request, 'landing_not_managed.html') |
| 3187 | 3213 | ||
| 3188 | def xhr_build(request): | ||
| 3189 | return render(request, 'landing_not_managed.html') | ||
| 3190 | |||
| 3191 | def xhr_projectinfo(request): | 3214 | def xhr_projectinfo(request): |
| 3192 | return render(request, 'landing_not_managed.html') | 3215 | return render(request, 'landing_not_managed.html') |
| 3193 | 3216 | ||
