From 46ec50744259f47005aec78bf1a4b94eb22efd50 Mon Sep 17 00:00:00 2001 From: Mira Weller Date: Tue, 11 Jun 2024 18:15:52 +0200 Subject: [PATCH] improve product list sorting ui (allow move between categories, hide up/down arrows if drag-drop is available) --- .../pretixcontrol/items/categories.html | 5 +- .../pretixcontrol/items/discounts.html | 24 +++++++--- .../templates/pretixcontrol/items/index.html | 46 ++++++++++++++----- src/pretix/control/urls.py | 2 +- src/pretix/control/views/item.py | 23 +++++----- .../pretixcontrol/js/ui/dragndroplist.js | 23 +++------- .../static/pretixcontrol/scss/main.scss | 8 ++++ 7 files changed, 79 insertions(+), 52 deletions(-) diff --git a/src/pretix/control/templates/pretixcontrol/items/categories.html b/src/pretix/control/templates/pretixcontrol/items/categories.html index e51de40720..503a057e4c 100644 --- a/src/pretix/control/templates/pretixcontrol/items/categories.html +++ b/src/pretix/control/templates/pretixcontrol/items/categories.html @@ -32,7 +32,6 @@ {% trans "Product categories" %} - @@ -41,12 +40,10 @@ {{ c.internal_name|default:c.name }} - + - - diff --git a/src/pretix/control/templates/pretixcontrol/items/discounts.html b/src/pretix/control/templates/pretixcontrol/items/discounts.html index b4622aeb9f..d908976c0e 100644 --- a/src/pretix/control/templates/pretixcontrol/items/discounts.html +++ b/src/pretix/control/templates/pretixcontrol/items/discounts.html @@ -56,8 +56,7 @@ {% trans "Internal name" %} - {% trans "Products" %} - + {% trans "Products" %} @@ -102,9 +101,10 @@ {% endif %} {% endif %} - + + {% if not d.benefit_same_products %}{% trans "Condition:" %}{% endif %} {% if d.condition_all_products %} - {% trans "All" %} + {% else %} {% endif %} - + {% if not d.benefit_same_products %} + + {% trans "Applies to:" %} + + + {% endif %} + - - {% trans "Products" %}

{% blocktrans trimmed %} @@ -29,7 +31,7 @@

{% csrf_token %}
- +
@@ -37,16 +39,23 @@ - - + - {% regroup items by category as cat_list %} - {% for c in cat_list %} - - {% for i in c.list %} - {% if forloop.counter0 == 0 and i.category %}{% endif %} + + {% for c, items in cat_list %} + {% if c %} + + + + {% endif %} + + {% for i in items %} + {% if forloop.counter0 == 0 and i.category %}{% endif %} - - + -
{% trans "Product name" %} {% trans "Category" %}Move{% trans "Default price" %} Edit
{{ i.category }}
{{ c }} + +
{% if not i.active %}{% endif %} @@ -110,13 +119,26 @@ title="{% trans "Can only be bought using a voucher" %}"> {% endif %} {% if i.category %}{{ i.category.name }}{% endif %} + + {% if i.free_price %} + + + {% endif %} + {{ i.default_price|money:request.event.currency }} + {% if i.original_price %}{{ i.original_price|money:request.event.currency }}{% endif %} + {% if i.tax_rule and i.default_price %} +
+ + {% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name|default:s_taxes %} + incl. {{ rate }}% {{ taxname }} + {% endblocktrans %} + + {% endif %} +
- diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index 1ce039366c..8a1c59b08b 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -293,7 +293,7 @@ urlpatterns = [ re_path(r'^items/(?P\d+)/$', item.ItemUpdateGeneral.as_view(), name='event.item'), re_path(r'^items/(?P\d+)/up$', item.item_move_up, name='event.items.up'), re_path(r'^items/(?P\d+)/down$', item.item_move_down, name='event.items.down'), - re_path(r'^items/reorder$', item.reorder_items, name='event.items.reorder'), + re_path(r'^items/reorder/(?P\d+)/$', item.reorder_items, name='event.items.reorder'), re_path(r'^items/(?P\d+)/delete$', item.ItemDelete.as_view(), name='event.items.delete'), re_path(r'^items/typeahead/meta/$', typeahead.item_meta_values, name='event.items.meta.typeahead'), re_path(r'^items/select2$', typeahead.items_select2, name='event.items.select2'), diff --git a/src/pretix/control/views/item.py b/src/pretix/control/views/item.py index 0b708310be..f64a4f13fc 100644 --- a/src/pretix/control/views/item.py +++ b/src/pretix/control/views/item.py @@ -35,6 +35,7 @@ import json from collections import OrderedDict, namedtuple +from itertools import groupby from json.decoder import JSONDecodeError from django.contrib import messages @@ -113,6 +114,8 @@ class ItemList(ListView): def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx['sales_channels'] = get_all_sales_channels() + items_by_category = {cat: list(items) for cat, items in groupby(ctx['items'], lambda item: item.category)} + ctx['cat_list'] = [(cat, items_by_category.get(cat, [])) for cat in [None, *self.request.event.categories.all()]] return ctx @@ -169,7 +172,7 @@ def item_move_down(request, organizer, event, item): @transaction.atomic @event_permission_required("can_change_items") @require_http_methods(["POST"]) -def reorder_items(request, organizer, event): +def reorder_items(request, organizer, event, category): try: ids = json.loads(request.body.decode('utf-8'))['ids'] except (JSONDecodeError, KeyError, ValueError): @@ -180,23 +183,21 @@ def reorder_items(request, organizer, event): if len(input_items) != len(ids): raise Http404(_("Some of the provided object ids are invalid.")) - item_categories = {i.category_id for i in input_items} - if len(item_categories) > 1: - raise Http404(_("You cannot reorder items spanning different categories.")) - - # get first and only category - item_category = next(iter(item_categories)) - if len(input_items) != request.event.items.filter(category=item_category).count(): - raise Http404(_("Not all objects have been selected.")) + if int(category): + target_category = request.event.categories.get(id=category) + else: + target_category = None for i in input_items: pos = ids.index(str(i.pk)) - if pos != i.position: # Save unneccessary UPDATE queries + if pos != i.position or target_category != i.category: # Save unneccessary UPDATE queries i.position = pos - i.save(update_fields=['position']) + i.category = target_category + i.save(update_fields=['position', 'category_id']) i.log_action( 'pretix.event.item.reordered', user=request.user, data={ 'position': i, + 'category': target_category and target_category.pk, } ) diff --git a/src/pretix/static/pretixcontrol/js/ui/dragndroplist.js b/src/pretix/static/pretixcontrol/js/ui/dragndroplist.js index 970374596a..b779262aae 100644 --- a/src/pretix/static/pretixcontrol/js/ui/dragndroplist.js +++ b/src/pretix/static/pretixcontrol/js/ui/dragndroplist.js @@ -6,7 +6,8 @@ $(function () { handle = $(''); container.find(".dnd-container").append(handle); - if (container.find("[data-dnd-id]").length < 2) { + container.find(".sortable-up, .sortable-down").hide(); + if (container.find("[data-dnd-id]").length < 2 && !container.data("dnd-group")) { handle.addClass("disabled"); return; } @@ -14,6 +15,7 @@ $(function () { Sortable.create(container.get(0), { filter: ".sortable-disabled", handle: ".dnd-sort-handle", + group: container.data("dnd-group"), onMove: function (evt) { return evt.related.className.indexOf('sortable-disabled') === -1; }, @@ -24,24 +26,11 @@ $(function () { onEnd: function (evt) { container.removeClass("sortable-dragarea"); container.parent().removeClass("sortable-sorting"); - - var disabledUp = container.find(".sortable-up:disabled"), - firstUp = container.find(">tr[data-dnd-id] .sortable-up").first(); - if (disabledUp.length && disabledUp.get(0) !== firstUp.get(0)) { - disabledUp.prop("disabled", false); - firstUp.prop("disabled", true); - } - - var disabledDown = container.find(".sortable-down:disabled"), - lastDown = container.find(">tr[data-dnd-id] .sortable-down").last(); - if (disabledDown.length && disabledDown.get(0) !== lastDown.get(0)) { - disabledDown.prop("disabled", false); - lastDown.prop("disabled", true); - } }, onSort: function (evt){ - var container = $(evt.to), - ids = container.find("[data-dnd-id]").toArray().map(function (e) { return e.dataset.dndId; }); + if (evt.target !== evt.to) return; + + var ids = container.find("[data-dnd-id]").toArray().map(function (e) { return e.dataset.dndId; }); $.ajax( { diff --git a/src/pretix/static/pretixcontrol/scss/main.scss b/src/pretix/static/pretixcontrol/scss/main.scss index 8e587ccc6a..d643189c75 100644 --- a/src/pretix/static/pretixcontrol/scss/main.scss +++ b/src/pretix/static/pretixcontrol/scss/main.scss @@ -841,6 +841,14 @@ h1 .label { tbody[data-dnd-url] { transition: opacity 1s; } +.table-items tbody + tbody { + border-top-width: 1px; +} +.table-items tbody[data-dnd-url]:after { + content:''; + display: table-row; + height: 0.5em; +} .sortable-sorting tbody:not(.sortable-dragarea) { opacity: .4; }