Show average run times for imports

This should give users a sense of when to start wondering if their
import isn't running after all.
This commit is contained in:
Mouse Reeve 2022-11-05 12:49:11 -07:00
parent 01d5274ebb
commit 4806a6273e
2 changed files with 61 additions and 15 deletions

View file

@ -7,12 +7,28 @@
{% block content %} {% block content %}
<div class="block"> <div class="block">
<h1 class="title">{% trans "Import Books" %}</h1> <h1 class="title">{% trans "Import Books" %}</h1>
{% if recent_avg_hours or recent_avg_minutes %}
<div class="notification">
<p>
{% if recent_avg_hours %}
{% blocktrans trimmed with hours=recent_avg_hours|floatformat:0|intcomma %}
On average, recent imports have taken {{ hours }} hours.
{% endblocktrans %}
{% else %}
{% blocktrans trimmed with minutes=recent_avg_minutes|floatformat:0|intcomma %}
On average, recent imports have taken {{ minutes }} minutes.
{% endblocktrans %}
{% endif %}
</p>
</div>
{% endif %}
<form class="box" name="import" action="/import" method="post" enctype="multipart/form-data"> <form class="box" name="import" action="/import" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<div class="columns"> <div class="columns">
<div class="column is-half"> <div class="column is-half">
<div class="field"> <div class="field">
<label class="label" for="source"> <label class="label" for="source">
{% trans "Data source:" %} {% trans "Data source:" %}
@ -21,19 +37,19 @@
<div class="select"> <div class="select">
<select name="source" id="source" aria-describedby="desc_source"> <select name="source" id="source" aria-describedby="desc_source">
<option value="Goodreads" {% if current == 'Goodreads' %}selected{% endif %}> <option value="Goodreads" {% if current == 'Goodreads' %}selected{% endif %}>
Goodreads (CSV) {% trans "Goodreads (CSV)" %}
</option> </option>
<option value="Storygraph" {% if current == 'Storygraph' %}selected{% endif %}> <option value="Storygraph" {% if current == 'Storygraph' %}selected{% endif %}>
Storygraph (CSV) {% trans "Storygraph (CSV)" %}
</option> </option>
<option value="LibraryThing" {% if current == 'LibraryThing' %}selected{% endif %}> <option value="LibraryThing" {% if current == 'LibraryThing' %}selected{% endif %}>
LibraryThing (TSV) {% trans "LibraryThing (TSV)" %}
</option> </option>
<option value="OpenLibrary" {% if current == 'OpenLibrary' %}selected{% endif %}> <option value="OpenLibrary" {% if current == 'OpenLibrary' %}selected{% endif %}>
OpenLibrary (CSV) {% trans "OpenLibrary (CSV)" %}
</option> </option>
<option value="Calibre" {% if current == 'Calibre' %}selected{% endif %}> <option value="Calibre" {% if current == 'Calibre' %}selected{% endif %}>
Calibre (CSV) {% trans "Calibre (CSV)" %}
</option> </option>
</select> </select>
</div> </div>
@ -81,5 +97,7 @@
<li><a href="{% url 'import-status' job.id %}">{{ job.created_date | naturaltime }}</a></li> <li><a href="{% url 'import-status' job.id %}">{{ job.created_date | naturaltime }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% include 'snippets/pagination.html' with page=jobs path=request.path %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,10 +1,14 @@
""" import books from another app """ """ import books from another app """
from io import TextIOWrapper from io import TextIOWrapper
import datetime
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db.models import Avg, ExpressionWrapper, F, fields
from django.core.paginator import Paginator
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from django.shortcuts import redirect from django.shortcuts import redirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.utils import timezone
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views import View from django.views import View
@ -17,6 +21,7 @@ from bookwyrm.importers import (
StorygraphImporter, StorygraphImporter,
OpenLibraryImporter, OpenLibraryImporter,
) )
from bookwyrm.settings import PAGE_LENGTH
# pylint: disable= no-self-use # pylint: disable= no-self-use
@method_decorator(login_required, name="dispatch") @method_decorator(login_required, name="dispatch")
@ -25,16 +30,39 @@ class Import(View):
def get(self, request): def get(self, request):
"""load import page""" """load import page"""
return TemplateResponse( jobs = models.ImportJob.objects.filter(user=request.user).order_by(
request, "-created_date"
"import/import.html",
{
"import_form": forms.ImportForm(),
"jobs": models.ImportJob.objects.filter(user=request.user).order_by(
"-created_date"
),
},
) )
paginated = Paginator(jobs, PAGE_LENGTH)
page = paginated.get_page(request.GET.get("page"))
data = {
"import_form": forms.ImportForm(),
"jobs": page,
"page_range": paginated.get_elided_page_range(
page.number, on_each_side=2, on_ends=1
),
}
last_week = timezone.now() - datetime.timedelta(days=7)
recent_avg = (
models.ImportJob.objects.filter(created_date__gte=last_week, complete=True)
.annotate(
runtime=ExpressionWrapper(
F("updated_date") - F("created_date"),
output_field=fields.DurationField(),
)
)
.aggregate(Avg("runtime"))
.get("runtime__avg")
)
if recent_avg:
seconds = recent_avg.total_seconds()
if seconds > 60**2:
data["recent_avg_hours"] = recent_avg.seconds / (60**2)
else:
data["recent_avg_minutes"] = recent_avg.seconds / 60
return TemplateResponse(request, "import/import.html", data)
def post(self, request): def post(self, request):
"""ingest a goodreads csv""" """ingest a goodreads csv"""