Hi Marius, Your patches passed functional testing, but I need you to re-do them a bit to get them merged -
- Can you please rebase your patchset on top of origin/master ? I have conflicts. - Please do not use Tab, but instead 4-spaces in the files; this is the current whitespace standard we use. Thanks, Alex On Fri, Aug 29, 2014 at 1:51 PM, Marius Avram <[email protected]> wrote: > Until now cookies were used to save which columns were shown and which > were hidden in toaster tables. The tables from the templates also have > functionalities like sorting the entries on a certain column and > limiting the number of entries displayed on a page. The later however > were not saved using cookies. This patch brings this new feature. > > The cookies are not saved only in the front-end. They are saved both > in the frontend in case the user uses the inputs/buttons to change > a parameter and also in the backend in case the user specifies manually > using GET variables the value of the parameters. > > When no GET parameters are given the views will redirect the url to one > containg the parameters saved as cookies. When no cookies exist, default > values will be used. > > [YOCTO #6126] > > Signed-off-by: Marius Avram <[email protected]> > --- > .../toastergui/templates/basetable_bottom.html | 15 ++- > .../toastergui/templates/basetable_top.html | 11 +- > bitbake/lib/toaster/toastergui/views.py | 122 > +++++++++++++------- > 3 files changed, 102 insertions(+), 46 deletions(-) > > diff --git > a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html > b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html > index ac14363..cbdc164 100644 > --- a/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html > +++ b/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html > @@ -26,7 +26,7 @@ > <span class="help-inline" > style="padding-top:5px;">Show rows:</span> > <select > style="margin-top:5px;margin-bottom:0px;" class="pagesize"> > {% with "2 5 10 25 50 100" as list%} > - {% for i in list.split %}<option{%if i == request.GET.count %} > selected{%endif%}>{{i}}</option> > + {% for i in list.split %}<option value="{{i}}">{{i}}</option> > {% endfor %} > {% endwith %} > </select> > @@ -56,6 +56,14 @@ > } > } > > + // load cookie for number of entries to be displayed on page > + pagesize = $.cookie('count'); > + if (!pagesize) > + pagesize = 10; > + $('.pagesize option').prop('selected', false) > + .filter('[value="' + pagesize + '"]') > + .attr('selected', true); > + > $('.chbxtoggle').each(function () { > showhideTableColumn($(this).attr('id'), $(this).is(':checked')) > }); > @@ -72,8 +80,9 @@ > $('.progress, .lead span').tooltip({container:'table', > placement:'top'}); > > $(".pagesize").change(function () { > - console.log("page size change"); > - reload_params({"count":$(this).val()}); ; > + reload_params({"count":$(this).val()}); > + // save cookie with pagesize > + $.cookie("count", $(this).val(), { path : > $(location).attr('pathname') }); > }); > }); > </script> > diff --git a/bitbake/lib/toaster/toastergui/templates/basetable_top.html > b/bitbake/lib/toaster/toastergui/templates/basetable_top.html > index 1231e1f..037554b 100644 > --- a/bitbake/lib/toaster/toastergui/templates/basetable_top.html > +++ b/bitbake/lib/toaster/toastergui/templates/basetable_top.html > @@ -156,6 +156,13 @@ > showhideImmediateTableAction( clname, sh, orderkey ); > } > > + // > + // saves a cookie with selected order field > + // > + function saveOrderCookie( orderfield ) { > + $.cookie("orderby", orderfield, { path: > $(location).attr('pathname') }); > + } > + > </script> > > <!-- control header --> > @@ -205,7 +212,7 @@ > <span class="help-inline" style="padding-top:5px;">Show > rows:</span> > <select style="margin-top:5px;margin-bottom:0px;" > class="pagesize"> > {% with "2 5 10 25 50 100" as list%} > -{% for i in list.split %} <option{%if i == > request.GET.count %} selected{%endif%}>{{i}}</option> > +{% for i in list.split %} <option > value="{{i}}">{{i}}</option> > {% endfor %} > {% endwith %} > </select> > @@ -221,7 +228,7 @@ > <tr> > {% for tc in tablecols %}<th class="{{tc.dclass}} > {{tc.clclass}}"> > {%if tc.qhelp%}<i class="icon-question-sign get-help" > title="{{tc.qhelp}}"></i>{%endif%} > - {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" > {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : > '{{tc.orderfield}}' })" >{{tc.name}}</a>{%else%}<span class="muted">{{ > tc.name}}</span>{%endif%} > + {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" > {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : > '{{tc.orderfield}}' })" onclick="saveOrderCookie('{{tc.orderfield}}')">{{ > tc.name}}</a>{%else%}<span class="muted">{{tc.name}}</span>{%endif%} > {%if tc.ordericon%} <i > class="icon-caret-{{tc.ordericon}}"></i>{%endif%} > {%if tc.filter%}<div class="btn-group pull-right"> > <a href="#filter_{{tc.filter.class}}" role="button" > class="btn btn-mini {%if > request.GET.filter%}{{tc.filter.options|filtered_icon:request.GET.filter}} > {%endif%}" {%if request.GET.filter and > tc.filter.options|filtered_tooltip:request.GET.filter %} > title="<p>{{tc.filter.options|filtered_tooltip:request.GET.filter}}</p><p><a > class='btn btn-small btn-primary' > href=javascript:reload_params({'filter':''})>Show all {% if > filter_search_display %}{{filter_search_display}}{% else %}{{objectname}}{% > endif %}</a></p>" {%endif%} data-toggle="modal"> <i class="icon-filter > filtered"></i> </a> > diff --git a/bitbake/lib/toaster/toastergui/views.py > b/bitbake/lib/toaster/toastergui/views.py > index bd65c08..d60b2f5 100755 > --- a/bitbake/lib/toaster/toastergui/views.py > +++ b/bitbake/lib/toaster/toastergui/views.py > @@ -20,6 +20,7 @@ > # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > > import operator,re > +import HTMLParser > > from django.db.models import Q, Sum > from django.db import IntegrityError > @@ -32,6 +33,7 @@ from django.core.urlresolvers import reverse > from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger > from django.http import HttpResponseBadRequest, HttpResponseNotFound > from django.utils import timezone > +from django.utils.html import escape > from datetime import timedelta > from django.utils import formats > import json > @@ -200,6 +202,22 @@ def _get_queryset(model, queryset, filter_string, > search_term, ordering_string, > # insure only distinct records (e.g. from multiple search hits) are > returned > return queryset.distinct() > > +# returns the value of entries per page and the name of the applied > sorting field. > +# if the value is given explicitly as a GET parameter it will be the > first selected, > +# otherwise the cookie value will be used. > +def _get_parameters_values(request, default_count, default_order): > + pagesize = request.GET.get('count', request.COOKIES.get('count', > default_count)) > + orderby = request.GET.get('orderby', request.COOKIES.get('orderby', > default_order)) > + return (pagesize, orderby) > + > + > +# set cookies for parameters. this is usefull in case parameters are set > +# manually from the GET values of the link > +def _save_parameters_cookies(response, pagesize, orderby, request): > + html_parser = HTMLParser.HTMLParser() > + response.set_cookie(key='count', value=pagesize, path=request.path) > + response.set_cookie(key='orderby', > value=html_parser.unescape(orderby), path=request.path) > + return response > > # shows the "all builds" page > def builds(request): > @@ -207,7 +225,8 @@ def builds(request): > # define here what parameters the view needs in the GET portion in > order to > # be able to display something. 'count' and 'page' are mandatory for > all views > # that use paginators. > - mandatory_parameters = { 'count': 10, 'page' : 1, 'orderby' : > 'completed_on:-' }; > + (pagesize, orderby) = _get_parameters_values(request, 10, > 'completed_on:-') > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : > orderby } > retval = _verify_parameters( request.GET, mandatory_parameters ) > if retval: > return _redirect_parameters( 'all-builds', request.GET, > mandatory_parameters) > @@ -220,7 +239,7 @@ def builds(request): > queryset = _get_queryset(Build, queryset_all, filter_string, > search_term, ordering_string, '-completed_on') > > # retrieve the objects that will be displayed in the table; builds a > paginator and gets a page range to display > - build_info = _build_page_range(Paginator(queryset, > request.GET.get('count', 10)),request.GET.get('page', 1)) > + build_info = _build_page_range(Paginator(queryset, pagesize), > request.GET.get('page', 1)) > > # build view-specific information; this is rendered specifically in > the builds page, at the top of the page (i.e. Recent builds) > build_mru = > Build.objects.filter(completed_on__gte=(timezone.now()-timedelta(hours=24))).order_by("-started_on")[:3] > @@ -379,7 +398,9 @@ def builds(request): > ] > } > > - return render(request, template, context) > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > > ## > @@ -548,8 +569,8 @@ def recipe(request, build_id, recipe_id): > > def target_common( request, build_id, target_id, variant ): > template = "target.html" > - default_orderby = 'name:+'; > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'name:+'}; > + (pagesize, orderby) = _get_parameters_values(request, 25, 'name:+') > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': > orderby } > retval = _verify_parameters( request.GET, mandatory_parameters ) > if retval: > return _redirect_parameters( > @@ -565,8 +586,7 @@ def target_common( request, build_id, target_id, > variant ): > packages_sum = queryset.aggregate( Sum( 'installed_size' )) > queryset = _get_queryset( > Package, queryset, filter_string, search_term, > ordering_string, 'name' ) > - packages = _build_page_range( Paginator( > - queryset, request.GET.get( 'count', 25 )),request.GET.get( > 'page', 1 )) > + packages = _build_page_range( Paginator(queryset, pagesize), > request.GET.get( 'page', 1 )) > > # bring in package dependencies > for p in packages.object_list: > @@ -690,7 +710,7 @@ his package', > 'objects' : packages, > 'packages_sum' : packages_sum[ 'installed_size__sum' ], > 'object_search_display': "packages included", > - 'default_orderby' : default_orderby, > + 'default_orderby' : orderby, > 'tablecols' : [ > tc_package, > tc_packageVersion, > @@ -707,7 +727,10 @@ his package', > tc_layerDir, > ] > } > - return( render( request, template, context )) > + > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def target( request, build_id, target_id ): > return( target_common( request, build_id, target_id, "target" )) > @@ -889,26 +912,25 @@ def tasks_common(request, build_id, variant, > task_anchor): > title_variant='Time' > object_search_display="time data" > filter_search_display="tasks" > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'elapsed_time:-'}; > - default_orderby = 'elapsed_time:-'; > + (pagesize, orderby) = _get_parameters_values(request, 25, > 'elapsed_time:-') > elif 'diskio' == variant: > title_variant='Disk I/O' > object_search_display="disk I/O data" > filter_search_display="tasks" > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'disk_io:-'}; > - default_orderby = 'disk_io:-'; > + (pagesize, orderby) = _get_parameters_values(request, 25, > 'disk_io:-') > elif 'cpuusage' == variant: > title_variant='CPU usage' > object_search_display="CPU usage data" > filter_search_display="tasks" > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'cpu_usage:-'}; > - default_orderby = 'cpu_usage:-'; > + (pagesize, orderby) = _get_parameters_values(request, 25, > 'cpu_usage:-') > else : > title_variant='Tasks' > object_search_display="tasks" > filter_search_display="tasks" > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'order:+'}; > - default_orderby = 'order:+'; > + (pagesize, orderby) = _get_parameters_values(request, 25, > 'order:+') > + > + > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': > orderby } > > template = 'tasks.html' > retval = _verify_parameters( request.GET, mandatory_parameters ) > @@ -934,7 +956,7 @@ def tasks_common(request, build_id, variant, > task_anchor): > del request.GET['anchor'] > i=0 > a=int(anchor) > - count_per_page=int(request.GET.get('count', 100)) > + count_per_page=int(pagesize) > for task in queryset.iterator(): > if a == task.order: > new_page= (i / count_per_page ) + 1 > @@ -943,7 +965,7 @@ def tasks_common(request, build_id, variant, > task_anchor): > return _redirect_parameters( variant, > request.GET, mandatory_parameters, build_id = build_id) > i += 1 > > - tasks = _build_page_range(Paginator(queryset, > request.GET.get('count', 100)),request.GET.get('page', 1)) > + tasks = _build_page_range(Paginator(queryset, > pagesize),request.GET.get('page', 1)) > > # define (and modify by variants) the 'tablecols' members > tc_order={ > @@ -1074,7 +1096,7 @@ def tasks_common(request, build_id, variant, > task_anchor): > 'title': title_variant, > 'build': Build.objects.filter(pk=build_id)[0], > 'objects': tasks, > - 'default_orderby' : default_orderby, > + 'default_orderby' : orderby, > 'search_term': search_term, > 'total_count': queryset_with_search.count(), > 'tablecols':[ > @@ -1091,7 +1113,9 @@ def tasks_common(request, build_id, variant, > task_anchor): > tc_log, > ]} > > - return render(request, template, context) > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def tasks(request, build_id): > return tasks_common(request, build_id, 'tasks', '') > @@ -1111,7 +1135,8 @@ def cpuusage(request, build_id): > > def recipes(request, build_id): > template = 'recipes.html' > - mandatory_parameters = { 'count': 100, 'page' : 1, > 'orderby':'name:+'}; > + (pagesize, orderby) = _get_parameters_values(request, 100, 'name:+') > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : > orderby } > retval = _verify_parameters( request.GET, mandatory_parameters ) > if retval: > return _redirect_parameters( 'recipes', request.GET, > mandatory_parameters, build_id = build_id) > @@ -1119,7 +1144,7 @@ def recipes(request, build_id): > queryset = > Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)) > queryset = _get_queryset(Recipe, queryset, filter_string, > search_term, ordering_string, 'name') > > - recipes = _build_page_range(Paginator(queryset, > request.GET.get('count', 100)),request.GET.get('page', 1)) > + recipes = _build_page_range(Paginator(queryset, > pagesize),request.GET.get('page', 1)) > > # prefetch the forward and reverse recipe dependencies > deps = { }; revs = { } > @@ -1218,8 +1243,9 @@ def recipes(request, build_id): > ] > } > > - return render(request, template, context) > - > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def configuration(request, build_id): > template = 'configuration.html' > @@ -1258,7 +1284,8 @@ def configuration(request, build_id): > > def configvars(request, build_id): > template = 'configvars.html' > - mandatory_parameters = { 'count': 100, 'page' : 1, > 'orderby':'variable_name:+', 'filter':'description__regex:.+'}; > + (pagesize, orderby) = _get_parameters_values(request, 100, > 'variable_name:+') > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : > orderby, 'filter' : 'description__regex:.+' } > retval = _verify_parameters( request.GET, mandatory_parameters ) > (filter_string, search_term, ordering_string) = > _search_tuple(request, Variable) > if retval: > @@ -1273,7 +1300,7 @@ def configvars(request, build_id): > # remove records where the value is empty AND there are no history > files > queryset = > queryset.exclude(variable_value='',vhistory__file_name__isnull=True) > > - variables = _build_page_range(Paginator(queryset, > request.GET.get('count', 50)), request.GET.get('page', 1)) > + variables = _build_page_range(Paginator(queryset, pagesize), > request.GET.get('page', 1)) > > # show all matching files (not just the last one) > file_filter= search_term + ":" > @@ -1339,12 +1366,14 @@ def configvars(request, build_id): > ], > } > > - return render(request, template, context) > - > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def bpackage(request, build_id): > template = 'bpackage.html' > - mandatory_parameters = { 'count': 100, 'page' : 1, > 'orderby':'name:+'}; > + (pagesize, orderby) = _get_parameters_values(request, 100, 'name:+') > + mandatory_parameters = { 'count' : pagesize, 'page' : 1, 'orderby' : > orderby } > retval = _verify_parameters( request.GET, mandatory_parameters ) > if retval: > return _redirect_parameters( 'packages', request.GET, > mandatory_parameters, build_id = build_id) > @@ -1352,7 +1381,7 @@ def bpackage(request, build_id): > queryset = Package.objects.filter(build = > build_id).filter(size__gte=0) > queryset = _get_queryset(Package, queryset, filter_string, > search_term, ordering_string, 'name') > > - packages = _build_page_range(Paginator(queryset, > request.GET.get('count', 100)),request.GET.get('page', 1)) > + packages = _build_page_range(Paginator(queryset, > pagesize),request.GET.get('page', 1)) > > context = { > 'objectname': 'packages built', > @@ -1432,7 +1461,9 @@ def bpackage(request, build_id): > ] > } > > - return render(request, template, context) > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def bfile(request, build_id, package_id): > template = 'bfile.html' > @@ -1587,7 +1618,8 @@ def package_built_detail(request, build_id, > package_id): > > # follow convention for pagination w/ search although not used for > this view > queryset = Package_File.objects.filter(package_id__exact=package_id) > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'path:+'}; > + (pagesize, orderby) = _get_parameters_values(request, 25, 'path:+') > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : > orderby } > retval = _verify_parameters( request.GET, mandatory_parameters ) > if retval: > return _redirect_parameters( 'package_built_detail', request.GET, > mandatory_parameters, build_id = build_id, package_id = package_id) > @@ -1618,7 +1650,10 @@ def package_built_detail(request, build_id, > package_id): > } > if paths.all().count() < 2: > context['disable_sort'] = True; > - return render(request, template, context) > + > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def package_built_dependencies(request, build_id, package_id): > template = "package_built_dependencies.html" > @@ -1643,9 +1678,9 @@ def package_included_detail(request, build_id, > target_id, package_id): > if Build.objects.filter(pk=build_id).count() == 0 : > return redirect(builds) > > - > # follow convention for pagination w/ search although not used for > this view > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'path:+'}; > + (pagesize, orderby) = _get_parameters_values(request, 25, 'path:+') > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : > orderby } > retval = _verify_parameters( request.GET, mandatory_parameters ) > if retval: > return _redirect_parameters( 'package_included_detail', > request.GET, mandatory_parameters, build_id = build_id, target_id = > target_id, package_id = package_id) > @@ -1680,8 +1715,10 @@ def package_included_detail(request, build_id, > target_id, package_id): > ] > } > if paths.all().count() < 2: > - context['disable_sort'] = True; > - return render(request, template, context) > + context['disable_sort'] = True > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def package_included_dependencies(request, build_id, target_id, > package_id): > template = "package_included_dependencies.html" > @@ -1710,7 +1747,8 @@ def package_included_reverse_dependencies(request, > build_id, target_id, package_ > if Build.objects.filter(pk=build_id).count() == 0 : > return redirect(builds) > > - mandatory_parameters = { 'count': 25, 'page' : 1, > 'orderby':'package__name:+'}; > + (pagesize, orderby) = _get_parameters_values(request, 25, > 'package__name:+') > + mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': > orderby } > retval = _verify_parameters( request.GET, mandatory_parameters ) > if retval: > return _redirect_parameters( > 'package_included_reverse_dependencies', request.GET, mandatory_parameters, > build_id = build_id, target_id = target_id, package_id = package_id) > @@ -1752,8 +1790,10 @@ def package_included_reverse_dependencies(request, > build_id, target_id, package_ > ] > } > if objects.all().count() < 2: > - context['disable_sort'] = True; > - return render(request, template, context) > + context['disable_sort'] = True > + response = render(request, template, context) > + _save_parameters_cookies(response, pagesize, orderby, request) > + return response > > def image_information_dir(request, build_id, target_id, packagefile_id): > # stubbed for now > -- > 1.7.9.5 > > -- > _______________________________________________ > toaster mailing list > [email protected] > https://lists.yoctoproject.org/listinfo/toaster > -- Alex Damian Yocto Project SSG / OTC
-- _______________________________________________ toaster mailing list [email protected] https://lists.yoctoproject.org/listinfo/toaster
