diff --git a/src/pretix/control/forms/__init__.py b/src/pretix/control/forms/__init__.py index 6f5fb6c08..a4adbe3d9 100644 --- a/src/pretix/control/forms/__init__.py +++ b/src/pretix/control/forms/__init__.py @@ -461,3 +461,31 @@ class SalesChannelCheckboxSelectMultiple(forms.CheckboxSelectMultiple): **super().create_option(name, value, label, selected, index, subindex, attrs), "plugin_missing": plugin and plugin not in self.event.get_plugins(), } + + +class ModelChoiceIteratorWithNone(forms.models.ModelChoiceIterator): + # see django.forms.models.ModelChoiceIterator for original implementation + def __iter__(self): + if self.field.empty_label is not None: + yield ("", self.field.empty_label) + if self.field.none_label is not None: + yield ("_none", self.field.none_label) + queryset = self.queryset + # Can't use iterator() when queryset uses prefetch_related() + if not queryset._prefetch_related_lookups: + queryset = queryset.iterator() + for obj in queryset: + yield self.choice(obj) + + +class ModelChoiceFieldWithNone(forms.ModelChoiceField): + iterator = ModelChoiceIteratorWithNone + + def __init__(self, *args, **kwargs): + self.none_label = kwargs.pop("none_label", None) + super().__init__(*args, **kwargs) + + def to_python(self, value): + if value == "_none": + return value + return super().to_python(value) diff --git a/src/pretix/control/forms/widgets.py b/src/pretix/control/forms/widgets.py index d054be63a..5773a8069 100644 --- a/src/pretix/control/forms/widgets.py +++ b/src/pretix/control/forms/widgets.py @@ -29,17 +29,30 @@ class Select2Mixin: super().__init__(*args, **kwargs) def options(self, name, value, attrs=None): - if value and value[0]: - for i, selected in enumerate(self.choices.queryset.filter(pk__in=value)): - yield self.create_option( - None, - self.choices.field.prepare_value(selected), - self.choices.field.label_from_instance(selected), - True, - i, - subindex=None, - attrs=attrs - ) + if not value or not value[0]: + return + has_none = "_none" in value + if has_none: + value = [v for v in value if v != "_none"] + yield self.create_option( + None, + "_none", + self.choices.field.none_label, + True, + 0, + subindex=None, + attrs=attrs + ) + for i, selected in enumerate(self.choices.queryset.filter(pk__in=value)): + yield self.create_option( + None, + self.choices.field.prepare_value(selected), + self.choices.field.label_from_instance(selected), + True, + i + (1 if has_none else 0), + subindex=None, + attrs=attrs + ) return def optgroups(self, name, value, attrs=None): diff --git a/src/pretix/control/views/typeahead.py b/src/pretix/control/views/typeahead.py index 30fa68315..e15c74379 100644 --- a/src/pretix/control/views/typeahead.py +++ b/src/pretix/control/views/typeahead.py @@ -145,11 +145,21 @@ def event_list(request): if 'can_copy' in request.GET: qs = EventWizardCopyForm.copy_from_queryset(request.user, request.session) else: - qs = request.user.get_events_with_any_permission(request) + permission = request.GET.get('permission') + if permission: + qs = request.user.get_events_with_permission(permission, request) + else: + qs = request.user.get_events_with_any_permission(request) + + name_slug_q = Q(name__icontains=i18ncomp(query)) | Q(slug__icontains=query) + organizer = request.GET.get('organizer') + if organizer: + qs = qs.filter(organizer__slug=organizer) + else: + name_slug_q |= Q(organizer__name__icontains=i18ncomp(query)) | Q(organizer__slug__icontains=query) qs = qs.filter( - Q(name__icontains=i18ncomp(query)) | Q(slug__icontains=query) | - Q(organizer__name__icontains=i18ncomp(query)) | Q(organizer__slug__icontains=query) + name_slug_q ).annotate( min_from=Min('subevents__date_from'), max_from=Max('subevents__date_from'), @@ -162,10 +172,19 @@ def event_list(request): total = qs.count() pagesize = 20 offset = (page - 1) * pagesize + results = [] + if page == 1 and 'include_none' in request.GET and not query: + results.append({ + 'id': "_none", + 'text': _("No event"), + 'name': _("No event"), + 'type': "event", + }) + results += [ + serialize_event(e) for e in qs.select_related('organizer')[offset:offset + pagesize] + ] doc = { - 'results': [ - serialize_event(e) for e in qs.select_related('organizer')[offset:offset + pagesize] - ], + 'results': results, 'pagination': { "more": total >= (offset + pagesize) } diff --git a/src/pretix/static/pretixcontrol/js/ui/main.js b/src/pretix/static/pretixcontrol/js/ui/main.js index 06c436192..9b48016b5 100644 --- a/src/pretix/static/pretixcontrol/js/ui/main.js +++ b/src/pretix/static/pretixcontrol/js/ui/main.js @@ -639,11 +639,13 @@ var form_handlers = function (el) { ).append(" ").append($("
").text(res.organizer).html()) ); } - $ret.append( - $("").addClass("event-daterange").append( - $("").addClass("fa fa-calendar fa-fw") - ).append(" ").append(res.date_range) - ); + if (res.date_range) { + $ret.append( + $("").addClass("event-daterange").append( + $("").addClass("fa fa-calendar fa-fw") + ).append(" ").append(res.date_range) + ); + } return $ret; }, }).on("select2:select", function () {