Event-list: pagination

This commit is contained in:
Klaas van Schelven
2024-09-26 10:39:36 +02:00
parent e83d1b8290
commit 336e126e3e
3 changed files with 173 additions and 4 deletions
+1 -2
View File
@@ -108,7 +108,7 @@
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/"><div class="p-4 font-bold hover:bg-slate-200 {% if tab == "stacktrace" %}text-cyan-500 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">Stacktrace</div></a>
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/details/"><div class="p-4 font-bold hover:bg-slate-200 {% if tab == "event-details" %}text-cyan-500 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">Event&nbsp;Details</div></a>
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/breadcrumbs/"><div class="p-4 font-bold hover:bg-slate-200 {% if tab == "breadcrumbs" %}text-cyan-500 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">Breadcrumbs</div></a>
{# <a href="/issues/issue/{{ issue.id }}/events/"><div class="p-4 font-bold hover:bg-slate-200 {% if tab == "event-list" %}text-cyan-500 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">Event&nbsp;List</div></a>#}
<a href="/issues/issue/{{ issue.id }}/events/"><div class="p-4 font-bold hover:bg-slate-200 {% if tab == "event-list" %}text-cyan-500 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">Event&nbsp;List</div></a>
<a href="/issues/issue/{{ issue.id }}/grouping/"><div class="p-4 font-bold hover:bg-slate-200 {% if tab == "grouping" %}text-cyan-500 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">Grouping</div></a>
<a href="/issues/issue/{{ issue.id }}/history/"><div class="p-4 font-bold hover:bg-slate-200 {% if tab == "history" %}text-cyan-500 border-cyan-500 border-b-4{% else %}text-slate-500 border-slate-400 hover:border-b-4{% endif %}">History</div></a>
</div>
@@ -134,7 +134,6 @@
<a href="/admin/issues/issue/{{ issue.id }}/change/">Issue Admin</a>
{% endif %}
</div>
</div>{# bottom nav bar #}
</div>{# the whole of the big tabbed view #}
+166 -2
View File
@@ -1,7 +1,171 @@
{% extends "issues/base.html" %}
{% load issues %}
{% block tab_content %}
{% for event in event_list %}
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/">{{ event.id }}</a><br>
{% comment %}
<div class="...">
<span class="...">
{% if page_obj.has_previous %}
<a href="?page=1">&laquo; first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span>
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
{% endif %}
</span>
</div>
{% endcomment %}
<div class="flex">
<div class="overflow-hidden">
<div class="italic">
Showing {{ page_obj.start_index }} - {{ page_obj.end_index }} of {{ page_obj.paginator.count }}
{% if project.digested_event_count != project.event_count %}
available events ({{ project.digested_event_count }} total observed).
{% else %}
total events.
{% endif %}
</div>
</div>
<div class="ml-auto flex-none">
{# UI / UX question: is it a good idea to reuse-with-different-meaning (pages, not events) for this? #}
{# adapted copy/pasta from _event_nav #}
<div class="flex place-content-end">
{% if page_obj.has_previous %} {# no need for 'is_first': if you can go to the left, you can go all the way to the left too #}
<a href="?page=1" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M3.22 7.595a.75.75 0 0 0 0 1.06l3.25 3.25a.75.75 0 0 0 1.06-1.06l-2.72-2.72 2.72-2.72a.75.75 0 0 0-1.06-1.06l-3.25 3.25Zm8.25-3.25-3.25 3.25a.75.75 0 0 0 0 1.06l3.25 3.25a.75.75 0 1 0 1.06-1.06l-2.72-2.72 2.72-2.72a.75.75 0 0 0-1.06-1.06Z" clip-rule="evenodd" />
</svg>
</a>
{% else %}
<div class="font-bold text-slate-300 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M3.22 7.595a.75.75 0 0 0 0 1.06l3.25 3.25a.75.75 0 0 0 1.06-1.06l-2.72-2.72 2.72-2.72a.75.75 0 0 0-1.06-1.06l-3.25 3.25Zm8.25-3.25-3.25 3.25a.75.75 0 0 0 0 1.06l3.25 3.25a.75.75 0 1 0 1.06-1.06l-2.72-2.72 2.72-2.72a.75.75 0 0 0-1.06-1.06Z" clip-rule="evenodd" />
</div>
{% endif %}
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>
</a>
{% else %}
<div class="font-bold text-slate-300 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>
</div>
{% endif %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>
</a>
{% else %}
<div class="font-bold text-slate-300 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>
</div>
{% endif %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.paginator.num_pages }}" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M12.78 7.595a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06l2.72-2.72-2.72-2.72a.75.75 0 0 1 1.06-1.06l3.25 3.25Zm-8.25-3.25 3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06l2.72-2.72-2.72-2.72a.75.75 0 0 1 1.06-1.06Z" clip-rule="evenodd" /></svg>
</a>
{% else %}
<div class="font-bold text-slate-300 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md inline-flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M12.78 7.595a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06l2.72-2.72-2.72-2.72a.75.75 0 0 1 1.06-1.06l3.25 3.25Zm-8.25-3.25 3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06l2.72-2.72-2.72-2.72a.75.75 0 0 1 1.06-1.06Z" clip-rule="evenodd" /></svg>
</div>
{% endif %}
</div>
</div>
</div>
<div class="pt-4">
<table class="w-full">
<thead>
<td class="p-4 align-top text-slate-800 font-bold">
#
</td>
<td class="p-4 align-top text-slate-800 font-bold">
ID
</td>
<td class="p-4 align-top text-slate-800 font-bold">
Timestamp
</td>
<td class="p-4 w-full align-top text-slate-800 font-bold">
Title
</td>
<td class="p-4 align-top text-slate-800 font-bold">
Release
</td>
<td class="p-4 align-top text-slate-800 font-bold">
Environment
</td>
</thead>
<tbody>
{% comment %}
TODO
release
environment
{% endcomment %}
{% for event in page_obj %}
<tr class="border-slate-200 border-2 ">
<td class="p-4 font-bold text-slate-500 align-top">
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/">{{ event.digest_order }}</a>
</td>
<td class="p-4 font-bold text-slate-500 align-top"> {# how useful is this really? #}
<a href="/issues/issue/{{ issue.id }}/event/{{ event.id }}/">{{ event.id|truncatechars:9 }}</a>
</td>
<td class="p-4 font-mono whitespace-nowrap align-top">
{{ event.timestamp|date:"j M G:i:s" }}.<span class="text-xs">{{ event.timestamp|date:"u"|slice:":3" }}</span>
</td>
{% comment %}
In the current setup, event title wraps to the next line if needed, there's no clipping.
I tried to get 'just use dots' to work for that, but I did not get that to work in a table. Perhaps it's actually
anti-thetical to the table layout. Perhaps if we used a flexbox layout, it would work better.
Anyway, overflow-to-next-line is also fine (at least for now)
{% endcomment %}
<td class="w-full p-4 font-mono align-top">
{{ event.title }}
</td>
<td class="p-4 font-mono align-top">
<span {% if event.release|issha %}class="font-mono"{% endif %}>{{ event.release|shortsha }}</span>
</td>
<td class="p-4 font-mono align-top">
{{ event.environment|truncatechars:30 }}
</td>
</tr>
{% endfor %}
{# note: no "empty" case; event-less issues are not something I expect to really support (for some definition of "really") #}
</tbody>
</table>
</div>
{% endblock %}
+6
View File
@@ -10,6 +10,7 @@ from django.template.defaultfilters import date
from django.urls import reverse
from django.core.exceptions import PermissionDenied
from django.http import Http404
from django.core.paginator import Paginator
from bugsink.decorators import project_membership_required, issue_membership_required, atomic_for_request_method
from bugsink.transaction import durable_atomic
@@ -479,6 +480,10 @@ def issue_event_list(request, issue):
return _handle_post(request, issue)
event_list = issue.event_set.all()
paginator = Paginator(event_list, 250) # in general "big is good" because it allows a lot "at a glance".
page_number = request.GET.get("page")
page_obj = paginator.get_page(page_number)
last_event = issue.event_set.order_by("timestamp").last() # the template needs this for the tabs, we pick the last
return render(request, "issues/event_list.html", {
@@ -490,6 +495,7 @@ def issue_event_list(request, issue):
"is_event_page": False,
"parsed_data": json.loads(last_event.data),
"mute_options": GLOBAL_MUTE_OPTIONS,
"page_obj": page_obj,
})