From afe06e313eac61f598f65e622ceb5951a9fabc9a Mon Sep 17 00:00:00 2001 From: Alexandru DAMIAN Date: Tue, 19 May 2015 16:14:29 +0100 Subject: [PATCH] bitbake: toaster: move project data typeahead to the REST API This patch enables JSON requests on the project REST endpoint, and replaces the universal queries "xhr_datatypeahead" with the `project` type to the REST project endpoint. The patch adds a decorator that takes a context returned by a view and either renders the template specified as the decorator argument, or converts the context to JSON. Normal "search", "filter" and "order" options for view work as normal on the JSON API format. To enable the JSON return, set the "format" GET parameter to "json". In order to demonstrate the functionality, the "New build" button is switched from using the xhr_datatypeahead to the project REST API with JSON formatting. Additionally, the XHR APIs that perform actions with the project id passed as parameter are removed, and the needed URLs are populated from the project JSON API returns after the project has been selected. (Bitbake rev: 15a2274eba13d19b864f337057d61c75ff7849cc) Signed-off-by: Alexandru DAMIAN Signed-off-by: Richard Purdie --- .../lib/toaster/toastergui/static/js/base.js | 51 +++++++---- .../toastergui/static/js/importlayer.js | 6 +- .../toastergui/static/js/layerdetails.js | 2 +- .../toastergui/static/js/libtoaster.js | 12 +-- .../toaster/toastergui/templates/base.html | 24 +++-- .../templates/basetable_bottom.html | 2 +- .../templates/detail_pagination_bottom.html | 2 +- .../toastergui/templatetags/projecttags.py | 4 +- bitbake/lib/toaster/toastergui/urls.py | 3 - bitbake/lib/toaster/toastergui/views.py | 89 ++++++++++++------- 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 ccc23e0e606..9424b6c3284 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) { /* Hide the change project icon when there is only one project */ if (ctx.numProjects == 1){ - $('#project .icon-pencil').hide(); + $('#project .icon-pencil').hide(); } newBuildButton.show().removeAttr("disabled"); + _checkProjectBuildable() _setupNewBuildButton(); function _checkProjectBuildable(){ - if (currentProjectId == undefined) + if (libtoaster.ctx.projectId == undefined) return; - libtoaster.getProjectInfo(ctx.projectInfoUrl, currentProjectId, + libtoaster.getProjectInfo(ctx.projectInfoUrl, libtoaster.ctx.projectId, function(data){ if (data.machine.name == undefined || data.layers.length == 0) { /* we can't build anything with out a machine and some layers */ @@ -53,18 +54,13 @@ function basePageInit (ctx) { /* If we don't have a current project then present the set project * form. */ - if (currentProjectId == undefined) { + if (libtoaster.ctx.projectId == undefined) { $('#change-project-form').show(); $('#project .icon-pencil').hide(); } - libtoaster.makeTypeahead(newBuildTargetInput, { type : "targets", project_id: currentProjectId }, function(item){ - /* successfully selected a target */ - selectedTarget = item; - }); - - libtoaster.makeTypeahead(newBuildProjectInput, { type : "projects" }, function(item){ + libtoaster.makeTypeahead(newBuildProjectInput, libtoaster.ctx.projectsUrl, { format : "json" }, function(item){ /* successfully selected a project */ newBuildProjectSaveBtn.removeAttr("disabled"); selectedProject = item; @@ -93,20 +89,40 @@ function basePageInit (ctx) { if (!selectedTarget) selectedTarget = { name: newBuildTargetInput.val() }; /* fire and forget */ - libtoaster.startABuild(ctx.projectBuildUrl, currentProjectId, selectedTarget.name, null, null); - window.location.replace(ctx.projectBasePageUrl+currentProjectId); + libtoaster.startABuild(ctx.projectBuildUrl, libtoaster.ctx.projectId, selectedTarget.name, null, null); + window.location.replace(libtoaster.ctx.projectPageUrl); }); newBuildProjectSaveBtn.click(function() { - currentProjectId = selectedProject.id + libtoaster.ctx.projectId = selectedProject.pk /* Update the typeahead project_id paramater */ _checkProjectBuildable(); - newBuildTargetInput.data('typeahead').options.xhrParams.project_id = currentProjectId; - newBuildTargetInput.val(""); - $("#new-build-button #project a").text(selectedProject.name).attr('href', ctx.projectBasePageUrl+currentProjectId); - $("#new-build-button .alert a").attr('href', ctx.projectBasePageUrl+currentProjectId); + /* we set the effective context of the page to the currently selected project */ + /* TBD: do we override even if we already have a context project ?? */ + /* TODO: replace global library context with references to the "selected" project */ + libtoaster.ctx.projectPageUrl = selectedProject.projectPageUrl; + libtoaster.ctx.xhrProjectEditUrl = selectedProject.xhrProjectEditUrl; + libtoaster.ctx.projectName = selectedProject.name; + libtoaster.ctx.projectId = selectedProject.id; + + ctx.projectBuildUrl = selectedProject.projectBuildUrl; + + /* we can create a target typeahead only after we have a project selected */ + newBuildTargetInput.prop("disabled", false); + newBuildTargetBuildBtn.prop("disabled", false); + + libtoaster.makeTypeahead(newBuildTargetInput, selectedProject.xhrProjectDataTypeaheadUrl, { type : "targets" }, function(item){ + /* successfully selected a target */ + selectedTarget = item; + }); + + newBuildTargetInput.val(""); + /* set up new form aspect */ + $("#new-build-button #project a").text(selectedProject.name).attr('href', libtoaster.ctx.projectPageUrl); + $("#new-build-button .alert a").attr('href', libtoaster.ctx.projectPageUrl); + $("#project .icon-pencil").show(); $("#change-project-form").slideUp({ 'complete' : function() { $("#new-build-button #project").show(); @@ -116,6 +132,7 @@ function basePageInit (ctx) { $('#new-build-button #project .icon-pencil').click(function() { newBuildProjectSaveBtn.attr("disabled", "disabled"); newBuildProjectInput.val($("#new-build-button #project a").text()); + $("#cancel-change-project").show(); $(this).parent().hide(); $("#change-project-form").slideDown(); }); diff --git a/bitbake/lib/toaster/toastergui/static/js/importlayer.js b/bitbake/lib/toaster/toastergui/static/js/importlayer.js index 875cc342b8b..beb2ede3dcf 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) { $("#new-project-button").hide(); - libtoaster.makeTypeahead(layerDepInput, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ + libtoaster.makeTypeahead(layerDepInput, libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ currentLayerDepSelection = item; layerDepBtn.removeAttr("disabled"); @@ -28,7 +28,7 @@ function importLayerPageInit (ctx) { /* We automatically add "openembedded-core" layer for convenience as a * dependency as pretty much all layers depend on this one */ - $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: "openembedded-core" }, function(layer) { + $.getJSON(libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: "openembedded-core" }, function(layer) { if (layer.list.length == 1) { currentLayerDepSelection = layer.list[0]; layerDepBtn.click(); @@ -211,7 +211,7 @@ function importLayerPageInit (ctx) { var name = $(this).val(); /* Check if the layer name exists */ - $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: name }, function(layer) { + $.getJSON(libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" , value: name }, function(layer) { if (layer.list.length > 0) { for (var i in layer.list){ 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 3746ea26e31..8e14b8f277d 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) { var addRmLayerBtn = $("#add-remove-layer-btn"); /* setup the dependencies typeahead */ - libtoaster.makeTypeahead(layerDepInput, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ + libtoaster.makeTypeahead(layerDepInput, libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type : "layers", project_id: libtoaster.ctx.projectId, include_added: "true" }, function(item){ currentLayerDepSelection = item; layerDepBtn.removeAttr("disabled"); diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js index 99e1f030959..72fb0a93f53 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 (){ * xhrUrl: the url to get the JSON from expects JSON in the form: * { "list": [ { "name": "test", "detail" : "a test thing" }, .... ] } * xhrParams: the data/parameters to pass to the getJSON url e.g. - * { 'type' : 'projects' } the text typed will be passed as 'value'. + * { 'type' : 'projects' } the text typed will be passed as 'search'. * selectedCB: function to call once an item has been selected one * arg of the item. */ - function _makeTypeahead (jQElement, xhrParams, selectedCB) { + function _makeTypeahead (jQElement, xhrUrl, xhrParams, selectedCB) { jQElement.typeahead({ source: function(query, process){ - xhrParams.value = query; - $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, this.options.xhrParams, function(data){ + xhrParams.search = query; + $.getJSON(xhrUrl, this.options.xhrParams, function(data){ if (data.error !== "ok") { console.log("Error getting data from server "+data.error); return; @@ -41,7 +41,7 @@ var libtoaster = (function (){ return $('').text(item.name).get(0); }, sorter: function (items) { return items; }, - xhrUrl: libtoaster.ctx.xhrDataTypeaheadUrl, + xhrUrl: xhrUrl, xhrParams: xhrParams, }); @@ -172,7 +172,7 @@ var libtoaster = (function (){ function _getLayerDepsForProject(projectId, layerId, onSuccess, onFail){ /* Check for dependencies not in the current project */ - $.getJSON(libtoaster.ctx.xhrDataTypeaheadUrl, + $.getJSON(libtoaster.ctx.xhrProjectDataTypeaheadUrl, { type: 'layerdeps', 'value': layerId , project_id: projectId }, function(data) { if (data.error != "ok") { diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html index 230dee49d64..e10dc116736 100644 --- a/bitbake/lib/toaster/toastergui/templates/base.html +++ b/bitbake/lib/toaster/toastergui/templates/base.html @@ -31,11 +31,19 @@ projectId : {{project.id|default:'undefined'}}, jsUrl : "{% static 'js/' %}", htmlUrl : "{% static 'html/' %}", + projectsUrl : "{% url 'all-projects' %}", {% if project.id %} - xhrDataTypeaheadUrl : "{% url 'xhr_datatypeahead' project.id %}", - xhrProjectEditUrl : "{% url 'xhr_projectedit' project.id %}", - projectPageUrl : "{% url 'project' project.id %}", - projectName : "{{project.name}}", + xhrProjectDataTypeaheadUrl : "{% url 'xhr_datatypeahead' project.id %}", + xhrProjectEditUrl : "{% url 'xhr_projectedit' project.id %}", + projectPageUrl : "{% url 'project' project.id %}", + projectName : "{{project.name}}", + projectId : {{project.id}}, + {% else %} + xhrProjectDataTypeaheadUrl : undefined, + xhrProjectEditUrl : undefined, + projectPageUrl : undefined, + projectName : undefined, + projectId : undefined, {% endif %} }; @@ -45,8 +53,6 @@ $(document).ready(function () { /* Vars needed for base.js */ var ctx = {}; - ctx.projectBuildUrl = "{% url 'xhr_build' %}"; - ctx.projectBasePageUrl = "{% url 'base_project' %}"; ctx.projectInfoUrl = "{% url 'xhr_projectinfo' %}"; ctx.numProjects = {{projects|length}}; ctx.currentUrl = "{{request.path|escapejs}}"; @@ -99,7 +105,7 @@
- Cancel +

View all projects

@@ -111,9 +117,9 @@
  • Recipe(s):
    - +
    - Build +
  • diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html index 4c28cae8105..ce023f51af6 100644 --- a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html +++ b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html @@ -57,7 +57,7 @@ } } - // load cookie for number of entries to be displayed on page + // load data for number of entries to be displayed on page if ({{request.GET.count}} != "") { pagesize = {{request.GET.count}}; } diff --git a/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html b/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html index 434facba936..f40c21d99fe 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 @@