From f439f5414206c94d486c60801a86acc57ad3f273 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 24 Aug 2015 11:05:47 +0100 Subject: [PATCH] Add delegate filter autocomplete support It would be helpful to provide autocomplete functionality for the delegate filter field, similar to that provided for the submitter field. This will provide a way to handle larger delegate lists without overloading the user with options. Add this functionality through use of Selectize, which is already used to provide similar functionality for filtering of "submitters". Signed-off-by: Stephen Finucane --- patchwork/filters.py | 92 +++++++++------------- patchwork/templates/patchwork/filters.html | 42 ++++++++++ patchwork/urls.py | 1 + patchwork/views/api.py | 56 +++++++++---- 4 files changed, 122 insertions(+), 69 deletions(-) diff --git a/patchwork/filters.py b/patchwork/filters.py index 4ee39982..eaa3e2b4 100644 --- a/patchwork/filters.py +++ b/patchwork/filters.py @@ -330,82 +330,64 @@ class ArchiveFilter(Filter): class DelegateFilter(Filter): param = 'delegate' - no_delegate_key = '-' - no_delegate_str = 'Nobody' - AnyDelegate = 1 def __init__(self, filters): super(DelegateFilter, self).__init__(filters) self.name = 'Delegate' - self.param = 'delegate' self.delegate = None + self.delegate_match = None - def _set_key(self, str): - if str == self.no_delegate_key: - self.applied = True - self.delegate = None + def _set_key(self, key): + self.delegate = None + self.delegate_match = None + delegate_id = None + + key = key.strip() + if not key: return try: - self.delegate = User.objects.get(id=str) - self.applied = True - except: + delegate_id = int(key) + except ValueError: pass + except: + return - def kwargs(self): - if not self.applied: - return {} - return {'delegate': self.delegate} - - def condition(self): - if self.delegate: - return self.delegate.profile.name() - return self.no_delegate_str - - def _form(self): - delegates = User.objects.filter( - profile__maintainer_projects=self.filters.project) - - str = '' + def condition(self): + if self.delegate: + return str(self.delegate) + elif self.delegate_match: + return self.delegate_match + return '' - return mark_safe(str) + def _form(self): + return mark_safe('') def key(self): if self.delegate: return self.delegate.id - if self.applied: - return self.no_delegate_key - return None - - def set_status(self, *args, **kwargs): - if 'delegate' in kwargs: - self.applied = self.forced = True - self.delegate = kwargs['delegate'] - if self.AnyDelegate in args: - self.applied = False - self.forced = True + return self.delegate_match filterclasses = [SubmitterFilter, StateFilter, diff --git a/patchwork/templates/patchwork/filters.html b/patchwork/templates/patchwork/filters.html index 3abfe249..f5c830b1 100644 --- a/patchwork/templates/patchwork/filters.html +++ b/patchwork/templates/patchwork/filters.html @@ -82,6 +82,48 @@ $(document).ready(function() { } }); }); + + +$(document).ready(function() { + $('#delegate_input').selectize({ + valueField: 'pk', + labelField: 'name', + searchField: ['name'], + plugins: ['enter_key_submit'], + maxItems: 1, + persist: false, + onInitialize: function() { + this.on('submit', function() { + if (!this.items.length) + this.$input.val(this.lastValue); + this.$input.closest('form').submit(); + }, this); + }, + render: { + option: function(item, escape) { + if (item.email) + return '
' + escape(item.name) + ' <' + + escape(item.email) + '>' + '
'; + return '
' + escape(item.name) + '
'; + }, + item: function(item, escape) { + return '
' + escape(item.name) + '
'; + } + }, + load: function(query, callback) { + req = $.ajax({ + url: '{% url 'api-delegates' %}?q=' + + encodeURIComponent(query) + '&l=10', + error: function() { + callback(); + }, + success: function(res) { + callback(res); + } + }); + } + }); +});
diff --git a/patchwork/urls.py b/patchwork/urls.py index 67167c18..550e5675 100644 --- a/patchwork/urls.py +++ b/patchwork/urls.py @@ -109,6 +109,7 @@ urlpatterns = [ # submitter autocomplete url(r'^submitter/$', api_views.submitters, name='api-submitters'), + url(r'^delegate/$', api_views.delegates, name='api-delegates'), # email setup url(r'^mail/$', mail_views.settings, name='mail-settings'), diff --git a/patchwork/views/api.py b/patchwork/views/api.py index 91f4f3d0..4d79f931 100644 --- a/patchwork/views/api.py +++ b/patchwork/views/api.py @@ -22,18 +22,20 @@ import json from django.db.models import Q from django.http import HttpResponse -from patchwork.models import Person +from patchwork.models import Person, User -def submitters(request): +MINIMUM_CHARACTERS = 3 + + +def _handle_request(request, queryset_fn, formatter): search = request.GET.get('q', '') limit = request.GET.get('l', None) - if len(search) <= 3: - return HttpResponse(content_type="application/json") + if len(search) < MINIMUM_CHARACTERS: + return HttpResponse(content_type='application/json') - queryset = Person.objects.filter(Q(name__icontains=search) | - Q(email__icontains=search)) + queryset = queryset_fn(search) if limit is not None: try: limit = int(limit) @@ -44,11 +46,37 @@ def submitters(request): queryset = queryset[:limit] data = [] - for submitter in queryset: - item = {} - item['pk'] = submitter.id - item['name'] = submitter.name - item['email'] = submitter.email - data.append(item) - - return HttpResponse(json.dumps(data), content_type="application/json") + for item in queryset: + data.append(formatter(item)) + + return HttpResponse(json.dumps(data), content_type='application/json') + + +def submitters(request): + def queryset(search): + return Person.objects.filter(Q(name__icontains=search) | + Q(email__icontains=search)) + + def formatter(submitter): + return { + 'pk': submitter.id, + 'name': submitter.name, + 'email': submitter.email, + } + + return _handle_request(request, queryset, formatter) + + +def delegates(request): + def queryset(search): + return User.objects.filter(Q(username__icontains=search) | + Q(first_name__icontains=search) | + Q(last_name__icontains=search)) + + def formatter(user): + return { + 'pk': user.id, + 'name': str(user), + } + + return _handle_request(request, queryset, formatter) -- 2.47.3