Improve UI to configure unavailable items handling (Z#23131828) (#3739)

* start impl of unavailability modes ui

* add db migration

* use new widget for more fields

* improve contrast

* use new widget for hide_without_voucher field

* improved wording

* rebase migration

* undo changes to require_membership_hidden

* code formatting

* move unavail_reason logic around

* enforce consistent state of hide_without_voucher / require_voucher

* annotate unavailability info in get_grouped_items

* remove MSIE6 compat

* add unavailability reasons to widget

* remove test output

* Apply suggestions from code review

text improvements

Co-authored-by: Richard Schreiber <schreiber@rami.io>

* add css fix for jumping items due to tooltip

* dynamically retrieve unavailability reason message

* widget: simplify logic conditions

* add available_{from,until}_mode to api and api docs

* rebase migration

* rebase migration

* add unavailable_*_mode to ItemVariation

* add available_*_mode to API docs for items

* fix wrong reference

* fix test cases

* add available_*_mode to item variation form

* apply unavailability modes to subevents and variations (presale)

* /o\

* apply unavailability modes to subevents and variations (widget)

* display unavailability mode in subevent product settings

* fix widget test

* fix api item tests

* copy available_*_mode when copying an item

* Apply suggestions from code review

Co-authored-by: Raphael Michel <michel@rami.io>

* Add unavail mode indicator to bulk create and edit forms

---------

Co-authored-by: Richard Schreiber <schreiber@rami.io>
Co-authored-by: Raphael Michel <michel@rami.io>
This commit is contained in:
Mira
2024-02-06 12:27:19 +01:00
committed by GitHub
parent 43facd1e43
commit 22f91f7aa2
30 changed files with 410 additions and 79 deletions

View File

@@ -0,0 +1,6 @@
{% with id=widget.attrs.id %}<div data-toggle="buttons"{% if id %} id="{{ id }}"{% endif %} class="btn-group btn-group-toggle {{ widget.attrs.class }}">{% for group, options, index in widget.optgroups %}
{% for option in options %}
{% include option.template_name with widget=option %}
{% endfor %}
{% endfor %}
</div>{% endwith %}

View File

@@ -0,0 +1,2 @@
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %} class="btn btn-primary-if-active form-field-boundary {% if widget.attrs.checked %} active{% endif %}" title="{{ widget.label }}" data-toggle="tooltip">
{% include "django/forms/widgets/input.html" %} <span class="fa fa-{{ widget.attrs.icon }}"></span></label>

View File

@@ -95,8 +95,8 @@
</div>
</div>
{% endif %}
{% bootstrap_field form.available_from layout="control" %}
{% bootstrap_field form.available_until layout="control" %}
{% bootstrap_field form.available_from visibility_field=form.available_from_mode layout="control_with_visibility" %}
{% bootstrap_field form.available_until visibility_field=form.available_until_mode layout="control_with_visibility" %}
{% bootstrap_field form.sales_channels layout="control" %}
{% bootstrap_field form.hide_without_voucher layout="control" %}
{% bootstrap_field form.require_approval layout="control" %}

View File

@@ -152,27 +152,28 @@
</fieldset>
<fieldset>
<legend>{% trans "Availability" %}</legend>
{% bootstrap_field form.sales_channels layout="control" %}
{% bootstrap_field form.available_from layout="control" %}
{% bootstrap_field form.available_until layout="control" %}
{% bootstrap_field form.max_per_order layout="control" %}
{% bootstrap_field form.min_per_order layout="control" %}
{% bootstrap_field form.require_voucher layout="control" %}
{% bootstrap_field form.hide_without_voucher layout="control" %}
{% bootstrap_field form.require_bundling layout="control" %}
{% bootstrap_field form.sales_channels layout="control" horizontal_field_class="col-md-7" %}
{% bootstrap_field form.available_from visibility_field=form.available_from_mode layout="control_with_visibility" %}
{% bootstrap_field form.available_until visibility_field=form.available_until_mode layout="control_with_visibility" %}
{% bootstrap_field form.max_per_order layout="control" horizontal_field_class="col-md-7" %}
{% bootstrap_field form.min_per_order layout="control" horizontal_field_class="col-md-7" %}
{% bootstrap_field form.require_voucher visibility_field=form.hide_without_voucher layout="control_with_visibility" %}
{% bootstrap_field form.require_bundling layout="control" horizontal_field_class="col-md-7" %}
{% if form.require_membership %}
{% bootstrap_field form.require_membership layout="control" %}
<div data-display-dependency="#{{ form.require_membership.id_for_label }}">
{% bootstrap_field form.require_membership_types layout="control" %}
{% bootstrap_field form.require_membership_hidden layout="control" %}
{% bootstrap_field form.require_membership_types layout="control" horizontal_field_class="col-md-7" %}
{% bootstrap_field form.require_membership_hidden layout="control" horizontal_field_class="col-md-7" %}
</div>
{% endif %}
{% bootstrap_field form.allow_cancel layout="control" %}
{% bootstrap_field form.allow_waitinglist layout="control" %}
{% bootstrap_field form.allow_cancel layout="control" horizontal_field_class="col-md-7" %}
{% bootstrap_field form.allow_waitinglist layout="control" horizontal_field_class="col-md-7" %}
{% if form.hidden_if_available %}
{% bootstrap_field form.hidden_if_available layout="control" %}
{% bootstrap_field form.hidden_if_available layout="control" horizontal_field_class="col-md-7" %}
{% endif %}
{% bootstrap_field form.hidden_if_item_available layout="control" %}
{% bootstrap_field form.hidden_if_item_available layout="control" horizontal_field_class="col-md-7" %}
</fieldset>
{% for v in formsets.values %}
<fieldset>

View File

@@ -503,11 +503,13 @@
</div>
<div class="form-group subevent-itemvar-group">
<div class="col-md-4 col-md-offset-3">
<label for="{{ f.rel_available_from.id_for_label }}" class="text-muted">{% trans "Available from" %}</label><br>
<label for="{{ f.rel_available_from.id_for_label }}" class="text-muted">{% trans "Available from" %}</label>
{% include "pretixcontrol/subevents/fragment_unavail_mode_indicator.html" with mode=f.available_from_mode %}<br>
{% bootstrap_field f.rel_available_from form_group_class="" layout="inline" %}
</div>
<div class="col-md-4">
<label for="{{ f.rel_available_until.id_for_label }}" class="text-muted">{% trans "Available until" %}</label><br>
<label for="{{ f.rel_available_until.id_for_label }}" class="text-muted">{% trans "Available until" %}</label>
{% include "pretixcontrol/subevents/fragment_unavail_mode_indicator.html" with mode=f.available_until_mode %}<br>
{% bootstrap_field f.rel_available_until form_group_class="" layout="inline" %}
</div>
</div>

View File

@@ -167,11 +167,13 @@
</div>
<div class="form-group subevent-itemvar-group">
<div class="col-md-4 col-md-offset-3">
<label for="{{ f.available_from.id_for_label }}" class="text-muted">{% trans "Available from" %}</label><br>
<label for="{{ f.available_from.id_for_label }}" class="text-muted">{% trans "Available from" %}</label>
{% include "pretixcontrol/subevents/fragment_unavail_mode_indicator.html" with mode=f.available_from_mode %}<br>
{% bootstrap_field f.available_from form_group_class="" layout="bulkedit_inline" %}
</div>
<div class="col-md-5">
<label for="{{ f.available_until.id_for_label }}" class="text-muted">{% trans "Available until" %}</label><br>
<label for="{{ f.available_until.id_for_label }}" class="text-muted">{% trans "Available until" %}</label>
{% include "pretixcontrol/subevents/fragment_unavail_mode_indicator.html" with mode=f.available_until_mode %}<br>
{% bootstrap_field f.available_until form_group_class="" layout="bulkedit_inline" %}
</div>
</div>

View File

@@ -145,11 +145,13 @@
</div>
<div class="form-group subevent-itemvar-group">
<div class="col-md-4 col-md-offset-3">
<label for="{{ f.available_from.id_for_label }}" class="text-muted">{% trans "Available from" %}</label><br>
{% bootstrap_field f.available_from form_group_class="" layout="inline" %}
<label for="{{ f.available_from.id_for_label }}" class="text-muted">{% trans "Available from" %}</label>
{% include "pretixcontrol/subevents/fragment_unavail_mode_indicator.html" with mode=f.available_from_mode %}<br>
{% bootstrap_field f.available_from form_group_class="foo" layout="inline" %}
</div>
<div class="col-md-4">
<label for="{{ f.available_until.id_for_label }}" class="text-muted">{% trans "Available until" %}</label><br>
<label for="{{ f.available_until.id_for_label }}" class="text-muted">{% trans "Available until" %}</label>
{% include "pretixcontrol/subevents/fragment_unavail_mode_indicator.html" with mode=f.available_until_mode %}<br>
{% bootstrap_field f.available_until form_group_class="" layout="inline" %}
</div>
</div>

View File

@@ -0,0 +1,6 @@
{% load i18n %}
{% if mode == "hide" %}
<span class="pull-right text-muted unavail-mode-indicator" data-toggle="tooltip" title="{% trans "Hide product if unavailable" %}. {% if f.variation %}{% trans "You can change this option in the variation settings." %}{% else %}{% trans "You can change this option in the product settings." %}{% endif %}"><span class="fa fa-eye-slash"></span></span>
{% else %}
<span class="pull-right text-muted unavail-mode-indicator" data-toggle="tooltip" title="{% trans "Show info text if unavailable" %}. {% if f.variation %}{% trans "You can change this option in the variation settings." %}{% else %}{% trans "You can change this option in the product settings." %}{% endif %}"><span class="fa fa-info-circle"></span></span>
{% endif %}