Amélioration de l'UX des imports récurrents

This commit is contained in:
Jean-Marie Favreau 2024-09-21 23:05:51 +02:00
parent ebfcf8823c
commit e04d94f97a
5 changed files with 67 additions and 71 deletions

View File

@ -58,7 +58,8 @@
<a class="badge simple" href="{% url 'add_event_urls' %}">{% picto_from_name "plus-circle" %} {% picto_from_name "calendar" %}</a> <a class="badge simple" href="{% url 'add_event_urls' %}">{% picto_from_name "plus-circle" %} {% picto_from_name "calendar" %}</a>
{% endif %} {% endif %}
{% if perms.agenda_culturel.view_recurrentimport %} {% if perms.agenda_culturel.view_recurrentimport %}
{% show_badge_failed_rimports "bottom" %} {% show_badge_rimports "bottom" "failed" %}
{% show_badge_rimports "bottom" "running" %}
{% endif %} {% endif %}
{% if perms.agenda_culturel.change_event %} {% if perms.agenda_culturel.change_event %}
{% show_badges_events "bottom" %} {% show_badges_events "bottom" %}

View File

@ -17,33 +17,38 @@
<div class="slide-buttons"> <div class="slide-buttons">
{% if not status %} {% if not status %}
<a href="{% url 'run_all_rimports' %}" role="button">Exécuter tout {% picto_from_name "play-circle" %}</a> <a href="{% url 'run_all_rimports' %}" role="button">Exécuter tout {% picto_from_name "play-circle" %}</a>
{% else %} {% else %}
{% if status == "failed" %} {% if status == "failed" or status == "canceled" %}
<a href="{% url 'run_all_rimports_failed' %}" role="button">Relancer les imports échoués {% picto_from_name "play-circle" %}</a> <a href="{% url 'run_all_rimports_status' status %}" role="button">Relancer les imports échoués {% picto_from_name "play-circle" %}</a>
{% endif %}
{% if status == "canceled" %}
<a href="{% url 'run_all_rimports_canceled' %}" role="button">Relancer les imports annulés {% picto_from_name "play-circle" %}</a>
{% endif %} {% endif %}
{% endif %} {% endif %}
<a href="{% url 'add_rimport'%}" role="button">Ajouter {% picto_from_name "plus-circle" %}</a> <a href="{% url 'add_rimport'%}" role="button">Ajouter {% picto_from_name "plus-circle" %}</a>
</div> </div>
<h1>Importations récurrentes {% if status %}<em>{{ status }}</em>{% endif %}</h1> <h1>Importations récurrentes {% if status %}<em>{{ status }}</em>{% endif %}</h1>
{% if status %} {% if status %}
<a href="{% url 'recurrent_imports' %}" role="button">tous ({{ nb_all }})</a> <a href="{% url 'recurrent_imports' %}">tous&nbsp;: {{ nb_all }}</a>
{% else %}
<strong>tous&nbsp;: {{ nb_all }}</strong>
{% endif %} {% endif %}
{% if not status or status != "failed" %} {% if nb_failed > 0 %}—
{% if nb_failed == 0 %} {% if not status or status != "failed" %}
<div role="button" class="secondary">échoués ({{ nb_failed }})</div> <a href="{% url 'recurrent_imports_status' 'failed' %}">échoués&nbsp;: {{ nb_failed }}</a>
{% else %} {% else %}
<a href="{% url 'recurrent_imports_failed' %}" role="button">échoués ({{ nb_failed }})</a> <strong>échoués&nbsp;: {{ nb_failed }}</strong>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if not status or status != "canceled" %} {% if nb_canceled > 0 %}—
{% if nb_canceled == 0 %} {% if not status or status != "canceled" %}
<div role="button" class="secondary">annulés ({{ nb_canceled }})</div> <a href="{% url 'recurrent_imports_status' 'canceled' %}">annulés&nbsp;: {{ nb_canceled }}</a>
{% else %} {% else %}
<a href="{% url 'recurrent_imports_canceled' %}" role="button">annulés ({{ nb_canceled }})</a> <strong>annulés&nbsp;: {{ nb_canceled }}</strong>
{% endif %}
{% endif %}
{% if nb_running > 0 %}—
{% if not status or status != "running" %}
<a href="{% url 'recurrent_imports_status' 'running' %}">en cours&nbsp;: {{ nb_running }}</a>
{% else %}
<strong>en cours&nbsp;: {{ nb_running }}</strong>
{% endif %} {% endif %}
{% endif %} {% endif %}
</header> </header>
@ -77,7 +82,11 @@
</td> </td>
<td> <td>
<div class="buttons"> <div class="buttons">
<a href="{% url 'run_rimport' obj.pk %}" role="button">Exécuter</a> {% if obj.last_import.status != "running" %}
<a href="{% url 'run_rimport' obj.pk %}" role="button">Exécuter</a>
{% else %}
<a href="{% url 'cancel_import' obj.last_import.pk %}" role="button">Annuler</a>
{% endif %}
<a href="{% url 'view_rimport' obj.pk %}" role="button">Consulter</a> <a href="{% url 'view_rimport' obj.pk %}" role="button">Consulter</a>
<a href="{% url 'edit_rimport' obj.pk %}" role="button">Modifier</a> <a href="{% url 'edit_rimport' obj.pk %}" role="button">Modifier</a>
</div> </div>

View File

@ -13,34 +13,43 @@ register = template.Library()
@register.simple_tag @register.simple_tag
def show_badge_failed_rimports(placement="top"): def show_badge_rimports(placement, status):
newest = BatchImportation.objects.filter(recurrentImport=OuterRef("pk")).order_by( newest = BatchImportation.objects.filter(recurrentImport=OuterRef("pk")).order_by(
"-created_date" "-created_date"
) )
nb_failed = ( nb = (
RecurrentImport.objects.annotate( RecurrentImport.objects.annotate(
last_run_status=Subquery(newest.values("status")[:1]) last_run_status=Subquery(newest.values("status")[:1])
) )
.filter(last_run_status=BatchImportation.STATUS.FAILED) .filter(last_run_status=status)
.count() .count()
) )
if nb_failed != 0: if status == BatchImportation.STATUS.FAILED:
suffix = 'en erreur'
picto = "alert-triangle"
cl = "error"
else:
suffix = ' en cours'
picto = "repeat"
cl = "simple"
if nb != 0:
return mark_safe( return mark_safe(
'<a href="' '<a href="'
+ reverse_lazy("recurrent_imports_failed") + reverse_lazy("recurrent_imports_status", args=[status])
+ '" class="badge error" data-placement="' + '" class="badge ' + cl + '" data-placement="'
+ placement + placement
+ '" data-tooltip="' + '" data-tooltip="'
+ str(nb_failed) + str(nb)
+ " importation" + " importation"
+ pluralize(nb_failed) + pluralize(nb)
+ " récurrente" + " récurrente"
+ pluralize(nb_failed) + pluralize(nb)
+ ' en erreur">' + ' ' + suffix + '">'
+ picto_from_name("alert-triangle") + picto_from_name(picto)
+ " " + " "
+ str(nb_failed) + str(nb)
+ "</a>" + "</a>"
) )
else: else:

View File

@ -71,10 +71,8 @@ urlpatterns = [
path("imports/<int:pk>/cancel", cancel_import, name="cancel_import"), path("imports/<int:pk>/cancel", cancel_import, name="cancel_import"),
path("rimports/", recurrent_imports, name="recurrent_imports"), path("rimports/", recurrent_imports, name="recurrent_imports"),
path("rimports/run", run_all_rimports, name="run_all_rimports"), path("rimports/run", run_all_rimports, name="run_all_rimports"),
path("rimports/failed", recurrent_imports_failed, name="recurrent_imports_failed"), path("rimports/status/<status>", recurrent_imports, name="recurrent_imports_status"),
path("rimports/failed/run", run_all_rimports_failed, name="run_all_rimports_failed"), path("rimports/status/<status>/run", run_all_rimports, name="run_all_rimports_status"),
path("rimports/canceled", recurrent_imports_canceled, name="recurrent_imports_canceled"),
path("rimports/canceled/run", run_all_rimports_canceled, name="run_all_rimports_canceled"),
path("rimports/add", RecurrentImportCreateView.as_view(), name="add_rimport"), path("rimports/add", RecurrentImportCreateView.as_view(), name="add_rimport"),
path("rimports/<int:pk>/view", view_rimport, name="view_rimport"), path("rimports/<int:pk>/view", view_rimport, name="view_rimport"),
path( path(

View File

@ -1147,16 +1147,6 @@ def cancel_import(request, pk):
## recurrent importations ## recurrent importations
######################### #########################
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.view_recurrentimport")
def recurrent_imports_failed(request):
return recurrent_imports(request, BatchImportation.STATUS.FAILED)
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.view_recurrentimport")
def recurrent_imports_canceled(request):
return recurrent_imports(request, BatchImportation.STATUS.CANCELED)
@login_required(login_url="/accounts/login/") @login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.view_recurrentimport") @permission_required("agenda_culturel.view_recurrentimport")
@ -1183,6 +1173,9 @@ def recurrent_imports(request, status=None):
nb_canceled = (events nb_canceled = (events
.filter(last_run_status=BatchImportation.STATUS.CANCELED) .filter(last_run_status=BatchImportation.STATUS.CANCELED)
.count()) .count())
nb_running = (events
.filter(last_run_status=BatchImportation.STATUS.RUNNING)
.count())
nb_all = events.count() nb_all = events.count()
@ -1194,7 +1187,7 @@ def recurrent_imports(request, status=None):
response = paginator.page(paginator.num_pages) response = paginator.page(paginator.num_pages)
return render( return render(
request, "agenda_culturel/rimports.html", {"paginator_filter": response, "nb_all": nb_all, "nb_failed": nb_failed, "nb_canceled": nb_canceled, "status": status} request, "agenda_culturel/rimports.html", {"paginator_filter": response, "nb_all": nb_all, "nb_failed": nb_failed, "nb_canceled": nb_canceled, "nb_running": nb_running, "status": status}
) )
@ -1274,39 +1267,25 @@ def run_rimport(request, pk):
@permission_required( @permission_required(
["agenda_culturel.view_recurrentimport", "agenda_culturel.run_recurrentimport"] ["agenda_culturel.view_recurrentimport", "agenda_culturel.run_recurrentimport"]
) )
def run_all_rimports(request): def run_all_rimports(request, status=None):
if request.method == "POST": if request.method == "POST":
# run recurrent import # run recurrent import
run_all_recurrent_imports.delay() if status == BatchImportation.STATUS.FAILED:
run_all_recurrent_imports_failed.delay()
elif status == BatchImportation.STATUS.CANCELED:
run_all_recurrent_imports_canceled.delay()
else:
run_all_recurrent_imports.delay()
messages.success(request, _("Imports has been launched.")) messages.success(request, _("Imports has been launched."))
return HttpResponseRedirect(reverse_lazy("recurrent_imports")) return HttpResponseRedirect(reverse_lazy("recurrent_imports"))
else: else:
return render(request, "agenda_culturel/run_all_rimports_confirm.html") if status == BatchImportation.STATUS.FAILED:
return render(request, "agenda_culturel/run_failed_rimports_confirm.html")
@login_required(login_url="/accounts/login/") elif status == BatchImportation.STATUS.CANCELED:
@permission_required( return render(request, "agenda_culturel/run_canceled_rimports_confirm.html")
["agenda_culturel.view_recurrentimport", "agenda_culturel.run_recurrentimport"] else:
) return render(request, "agenda_culturel/run_all_rimports_confirm.html")
def run_all_rimports_failed(request):
if request.method == "POST":
# run recurrent import
run_all_recurrent_imports_failed.delay()
messages.success(request, _("Imports has been launched."))
return HttpResponseRedirect(reverse_lazy("recurrent_imports"))
else:
return render(request, "agenda_culturel/run_failed_rimports_confirm.html")
def run_all_rimports_canceled(request):
if request.method == "POST":
# run recurrent import
run_all_recurrent_imports_canceled.delay()
messages.success(request, _("Imports has been launched."))
return HttpResponseRedirect(reverse_lazy("recurrent_imports"))
else:
return render(request, "agenda_culturel/run_canceled_rimports_confirm.html")
######################### #########################