From ec8e07f8cf4d04d9e7a4a5e66103d28ba4a81ed4 Mon Sep 17 00:00:00 2001 From: Dave Lerner Date: Tue, 24 Feb 2015 16:14:41 -0600 Subject: bitbake: toaster: add sort, search, paging to recipe package page When selecting the packages tab on a recipe detail page, the page now includes: column sort on package name and size columns, search on the package name, and pagination. Column sort is added by splitting the recipe view/html for a recipe's package list into a new url path, view name and template, so that the sorting routine, views.reload_params(), interfaces similar to other views. Search, sorting, and pagination are implemented for this detail page using three new templates. templates/detail_pagination_bottom.html templates/detail_search_header.html templates/detail_sorted_header.html views.recipe() is optimized since the recipe's package list is no longer needed by the recipe template, only the recipe's package count is required for the first page. The recipe view and template also changes to support tabbing to the right context on the recipe detail page from the recipe-package page. [YOCTO #6154] (Bitbake rev: 6cb9e853d05c2c71467af22ef459ffbe6f41de36) Signed-off-by: Dave Lerner Signed-off-by: Richard Purdie --- .../templates/detail_pagination_bottom.html | 60 ++++++++++ .../toastergui/templates/detail_search_header.html | 68 ++++++++++++ .../toastergui/templates/detail_sorted_header.html | 25 +++++ .../lib/toaster/toastergui/templates/recipe.html | 52 ++------- .../toastergui/templates/recipe_packages.html | 123 +++++++++++++++++++++ bitbake/lib/toaster/toastergui/urls.py | 2 + bitbake/lib/toaster/toastergui/views.py | 60 +++++++++- 7 files changed, 342 insertions(+), 48 deletions(-) create mode 100644 bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html create mode 100644 bitbake/lib/toaster/toastergui/templates/detail_search_header.html create mode 100644 bitbake/lib/toaster/toastergui/templates/detail_sorted_header.html create mode 100644 bitbake/lib/toaster/toastergui/templates/recipe_packages.html (limited to 'bitbake') diff --git a/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html b/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html new file mode 100644 index 0000000000..355ae9073c --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html @@ -0,0 +1,60 @@ +{% comment %} + Show pagination controls as per search/pagination table detail spec. + Input: objects, setup for pagination using the standard method in views. + object_count, count for complete list of objects, (all pages, no pattern) +{% endcomment %} + +{# only paginate if 10 or more rows unfiltered, all pages #} +{% if object_count >= 10 %} + + + + +{% endif %} + diff --git a/bitbake/lib/toaster/toastergui/templates/detail_search_header.html b/bitbake/lib/toaster/toastergui/templates/detail_search_header.html new file mode 100644 index 0000000000..ca8e158cb1 --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/detail_search_header.html @@ -0,0 +1,68 @@ +{% comment %} + Show a detail table Search field and Rows per page. + Input: + objects, our boilerplated paginated with search fields set. + object_count, count of full, unfiltered, objects list + search_what, fills in "Search ___" + Only show the search form if we have more than 10 results, + or if return from a previous search. +{% endcomment %} + + + +
+{% if objects.paginator.count > 10 or request.GET.search %} + {% if objects.paginator.count == 0 %} +
+

No {{search_what}} found

+
+ {% else %} + + {% endif %} + + + + + {% if request.GET.search %} + + + + {% endif %} + + {% if objects.paginator.count == 0 %} + + {% endif %} +
+{% endif %} + +{% if objects.paginator.count == 0 %} +
{# end alert #} +{% else %} + {% if object_count > 10 %} +
+ Show rows: + +
+ {% endif %} +{% endif %} +
{# row-fluid #} diff --git a/bitbake/lib/toaster/toastergui/templates/detail_sorted_header.html b/bitbake/lib/toaster/toastergui/templates/detail_sorted_header.html new file mode 100644 index 0000000000..a7917dcf5a --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/detail_sorted_header.html @@ -0,0 +1,25 @@ +{% comment %} + Adds sorted columns to a detail table. + Must be preceded by + Must be followed by ...
. + Requires tablecols setup column fields dclass, clclass, qhelp, orderfield. +{% endcomment %} +{% load projecttags %} +{# #} + + + + {% for tc in tablecols %}{% endfor %} + + + diff --git a/bitbake/lib/toaster/toastergui/templates/recipe.html b/bitbake/lib/toaster/toastergui/templates/recipe.html index 621b852e77..6eba9b6f0b 100644 --- a/bitbake/lib/toaster/toastergui/templates/recipe.html +++ b/bitbake/lib/toaster/toastergui/templates/recipe.html @@ -19,25 +19,25 @@
+ {%if tc.qhelp%}{%endif%} + {%if tc.orderfield%}{{tc.name}}{%else%}{{tc.name}}{%endif%} + {%if tc.ordericon%} {%endif%} + {% if request.GET.search and forloop.first %} + {{objects.paginator.count}} + {% endif %} + {%if tc.filter%}
+ +
{%endif%} +
{% endif %} -
- {% if not packages %} -
- {{object.name}}_{{object.version}} does not build any packages. -
- {% else %} - - - - - - - - - - - {% for package in packages|dictsort:"name" %} - - - - - - - - {% endfor %} - - -
- Package - - Version - - Size -
{{package.name}}{{package.version}}_{{package.revision}}{{package.size|filtered_filesizeformat}}
- {% endif %} -
-
+
{% if not object.r_dependencies_recipe.all %}
@@ -212,7 +176,7 @@ {% endif %}
-
+
{% if not object.r_dependencies_depends.all %}
diff --git a/bitbake/lib/toaster/toastergui/templates/recipe_packages.html b/bitbake/lib/toaster/toastergui/templates/recipe_packages.html new file mode 100644 index 0000000000..d25847bc0d --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/recipe_packages.html @@ -0,0 +1,123 @@ +{% extends "basebuilddetailpage.html" %} + +{% load projecttags %} +{% load humanize %} +{% block localbreadcrumb %} +
  • Recipes
  • +
  • {{recipe.name}}_{{recipe.version}}
  • +{% endblock %} + +{% block pagedetailinfomain %} + + + +
    + +
    + +
    + +
    +{#
    #} +
    + {% if not objects and not request.GET.search %} +
    + {{recipe.name}}_{{recipe.version}} does not build any packages. +
    + + {% elif not objects %} + {# have empty search results, no table nor pagination #} + {% with "packages" as search_what %} + {% include "detail_search_header.html" %} + {% endwith %} + + {% else %} + + + {% with "packages" as search_what %} + {% include "detail_search_header.html" %} + {% endwith %} + + {% include "detail_sorted_header.html" %} + + + {% for package in objects %} + + + + + + + + {% endfor %} + + {% endif %} + {% if objects %} + +
    {{package.name}}{{package.version}}_{{package.revision}}{{package.size|filtered_filesizeformat}}
    + {% include "detail_pagination_bottom.html" %} + {% endif %} +
    {# tab-pane #} +
    {# tab-content #} +
    {# span7 #} + +
    +

    About {{recipe.name}}

    +
    + {% if recipe.summary %} +
    Summary
    +
    {{recipe.summary}}
    + {% endif %} + {% if recipe.description %} +
    Description
    +
    {{recipe.description}}
    + {% endif %} + {% if recipe.homepage %} +
    Homepage
    +
    {{recipe.homepage}}
    + {% endif %} + {% if recipe.bugtracker %} +
    Bugtracker
    +
    {{recipe.bugtracker}}
    + {% endif %} + {% if recipe.section %} +
    + Section + +
    +
    {{recipe.section}}
    + {% endif %} + {% if recipe.license %} +
    License
    +
    {{recipe.license}}
    + {% endif %} +
    +
    +{% endblock pagedetailinfomain %} diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 1c83090f58..fc03f19a7f 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py @@ -32,7 +32,9 @@ urlpatterns = patterns('toastergui.views', url(r'^build/(?P\d+)/task/(?P\d+)$', 'task', name='task'), url(r'^build/(?P\d+)/recipes/$', 'recipes', name='recipes'), + url(r'^build/(?P\d+)/recipe/(?P\d+)/active_tab/(?P\d{1})$', 'recipe', name='recipe'), url(r'^build/(?P\d+)/recipe/(?P\d+)$', 'recipe', name='recipe'), + url(r'^build/(?P\d+)/recipe_packages/(?P\d+)$', 'recipe_packages', name='recipe_packages'), url(r'^build/(?P\d+)/packages/$', 'bpackage', name='packages'), url(r'^build/(?P\d+)/package/(?P\d+)$', 'package_built_detail', diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 4f4ae67ca7..ed27ca0ac9 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py @@ -419,8 +419,7 @@ def task( request, build_id, task_id ): return render( request, template, context ) - -def recipe(request, build_id, recipe_id): +def recipe(request, build_id, recipe_id, active_tab="1"): template = "recipe.html" if Recipe.objects.filter(pk=recipe_id).count() == 0 : return redirect(builds) @@ -429,7 +428,12 @@ def recipe(request, build_id, recipe_id): layer_version = Layer_Version.objects.get(pk=object.layer_version_id) layer = Layer.objects.get(pk=layer_version.layer_id) tasks = Task.objects.filter(recipe_id = recipe_id, build_id = build_id).exclude(order__isnull=True).exclude(task_name__endswith='_setscene').exclude(outcome=Task.OUTCOME_NA) - packages = Package.objects.filter(recipe_id = recipe_id).filter(build_id = build_id).filter(size__gte=0) + package_count = Package.objects.filter(recipe_id = recipe_id).filter(build_id = build_id).filter(size__gte=0).count() + + if active_tab != '1' and active_tab != '3' and active_tab != '4' : + active_tab = '1' + tab_states = {'1': '', '3': '', '4': ''} + tab_states[active_tab] = 'active' context = { 'build' : Build.objects.get(pk=build_id), @@ -437,10 +441,58 @@ def recipe(request, build_id, recipe_id): 'layer_version' : layer_version, 'layer' : layer, 'tasks' : tasks, - 'packages': packages, + 'package_count' : package_count, + 'tab_states' : tab_states, } return render(request, template, context) +def recipe_packages(request, build_id, recipe_id): + template = "recipe_packages.html" + if Recipe.objects.filter(pk=recipe_id).count() == 0 : + return redirect(builds) + + (pagesize, orderby) = _get_parameters_values(request, 10, 'name:+') + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': orderby } + retval = _verify_parameters( request.GET, mandatory_parameters ) + if retval: + return _redirect_parameters( 'recipe_packages', request.GET, mandatory_parameters, build_id = build_id, recipe_id = recipe_id) + (filter_string, search_term, ordering_string) = _search_tuple(request, Package) + + recipe = Recipe.objects.get(pk=recipe_id) + queryset = Package.objects.filter(recipe_id = recipe_id).filter(build_id = build_id).filter(size__gte=0) + package_count = queryset.count() + queryset = _get_queryset(Package, queryset, filter_string, search_term, ordering_string, 'name') + + packages = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1)) + + context = { + 'build' : Build.objects.get(pk=build_id), + 'recipe' : recipe, + 'objects' : packages, + 'object_count' : package_count, + 'tablecols':[ + { + 'name':'Package', + 'orderfield': _get_toggle_order(request,"name"), + 'ordericon': _get_toggle_order_icon(request,"name"), + 'orderkey': "name", + }, + { + 'name':'Version', + }, + { + 'name':'Size', + 'orderfield': _get_toggle_order(request,"size", True), + 'ordericon': _get_toggle_order_icon(request,"size"), + 'orderkey': 'size', + 'dclass': 'sizecol span2', + }, + ] + } + response = render(request, template, context) + _save_parameters_cookies(response, pagesize, orderby, request) + return response + def target_common( request, build_id, target_id, variant ): template = "target.html" (pagesize, orderby) = _get_parameters_values(request, 25, 'name:+') -- cgit v1.2.3-54-g00ecf