FossilRepo
Add pagination for tickets, improve code line number spacing - Ticket list: pagination controls (prev/next), total count display - Tickets loaded in batches of 50 with page navigation - Code file viewer: added border-right separator on line numbers, increased padding between line numbers and code content
Commit
f3d894cc90e2682de903bec72a3027f627b60331ed1826ed36eb3447fa0d1e35
Parent
04985a1f1d0a887…
3 files changed
+12
-1
+3
-2
+17
+12
-1
| --- fossil/views.py | ||
| +++ fossil/views.py | ||
| @@ -420,16 +420,23 @@ | ||
| 420 | 420 | P.PROJECT_VIEW.check(request.user) |
| 421 | 421 | project, fossil_repo, reader = _get_repo_and_reader(slug) |
| 422 | 422 | |
| 423 | 423 | status_filter = request.GET.get("status", "") |
| 424 | 424 | search = request.GET.get("search", "").strip() |
| 425 | + page = int(request.GET.get("page", "1")) | |
| 426 | + per_page = 50 | |
| 425 | 427 | |
| 426 | 428 | with reader: |
| 427 | - tickets = reader.get_tickets(status=status_filter or None) | |
| 429 | + tickets = reader.get_tickets(status=status_filter or None, limit=500) | |
| 428 | 430 | |
| 429 | 431 | if search: |
| 430 | 432 | tickets = [t for t in tickets if search.lower() in t.title.lower()] |
| 433 | + | |
| 434 | + total = len(tickets) | |
| 435 | + tickets = tickets[(page - 1) * per_page : page * per_page] | |
| 436 | + has_next = page * per_page < total | |
| 437 | + has_prev = page > 1 | |
| 431 | 438 | |
| 432 | 439 | if request.headers.get("HX-Request"): |
| 433 | 440 | return render(request, "fossil/partials/ticket_table.html", {"tickets": tickets, "project": project}) |
| 434 | 441 | |
| 435 | 442 | return render( |
| @@ -439,10 +446,14 @@ | ||
| 439 | 446 | "project": project, |
| 440 | 447 | "fossil_repo": fossil_repo, |
| 441 | 448 | "tickets": tickets, |
| 442 | 449 | "status_filter": status_filter, |
| 443 | 450 | "search": search, |
| 451 | + "page": page, | |
| 452 | + "has_next": has_next, | |
| 453 | + "has_prev": has_prev, | |
| 454 | + "total": total, | |
| 444 | 455 | "active_tab": "tickets", |
| 445 | 456 | }, |
| 446 | 457 | ) |
| 447 | 458 | |
| 448 | 459 | |
| 449 | 460 |
| --- fossil/views.py | |
| +++ fossil/views.py | |
| @@ -420,16 +420,23 @@ | |
| 420 | P.PROJECT_VIEW.check(request.user) |
| 421 | project, fossil_repo, reader = _get_repo_and_reader(slug) |
| 422 | |
| 423 | status_filter = request.GET.get("status", "") |
| 424 | search = request.GET.get("search", "").strip() |
| 425 | |
| 426 | with reader: |
| 427 | tickets = reader.get_tickets(status=status_filter or None) |
| 428 | |
| 429 | if search: |
| 430 | tickets = [t for t in tickets if search.lower() in t.title.lower()] |
| 431 | |
| 432 | if request.headers.get("HX-Request"): |
| 433 | return render(request, "fossil/partials/ticket_table.html", {"tickets": tickets, "project": project}) |
| 434 | |
| 435 | return render( |
| @@ -439,10 +446,14 @@ | |
| 439 | "project": project, |
| 440 | "fossil_repo": fossil_repo, |
| 441 | "tickets": tickets, |
| 442 | "status_filter": status_filter, |
| 443 | "search": search, |
| 444 | "active_tab": "tickets", |
| 445 | }, |
| 446 | ) |
| 447 | |
| 448 | |
| 449 |
| --- fossil/views.py | |
| +++ fossil/views.py | |
| @@ -420,16 +420,23 @@ | |
| 420 | P.PROJECT_VIEW.check(request.user) |
| 421 | project, fossil_repo, reader = _get_repo_and_reader(slug) |
| 422 | |
| 423 | status_filter = request.GET.get("status", "") |
| 424 | search = request.GET.get("search", "").strip() |
| 425 | page = int(request.GET.get("page", "1")) |
| 426 | per_page = 50 |
| 427 | |
| 428 | with reader: |
| 429 | tickets = reader.get_tickets(status=status_filter or None, limit=500) |
| 430 | |
| 431 | if search: |
| 432 | tickets = [t for t in tickets if search.lower() in t.title.lower()] |
| 433 | |
| 434 | total = len(tickets) |
| 435 | tickets = tickets[(page - 1) * per_page : page * per_page] |
| 436 | has_next = page * per_page < total |
| 437 | has_prev = page > 1 |
| 438 | |
| 439 | if request.headers.get("HX-Request"): |
| 440 | return render(request, "fossil/partials/ticket_table.html", {"tickets": tickets, "project": project}) |
| 441 | |
| 442 | return render( |
| @@ -439,10 +446,14 @@ | |
| 446 | "project": project, |
| 447 | "fossil_repo": fossil_repo, |
| 448 | "tickets": tickets, |
| 449 | "status_filter": status_filter, |
| 450 | "search": search, |
| 451 | "page": page, |
| 452 | "has_next": has_next, |
| 453 | "has_prev": has_prev, |
| 454 | "total": total, |
| 455 | "active_tab": "tickets", |
| 456 | }, |
| 457 | ) |
| 458 | |
| 459 | |
| 460 |
+3
-2
| --- templates/fossil/code_file.html | ||
| +++ templates/fossil/code_file.html | ||
| @@ -6,18 +6,19 @@ | ||
| 6 | 6 | <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> |
| 7 | 7 | <style> |
| 8 | 8 | .code-table { border-collapse: collapse; width: 100%; } |
| 9 | 9 | .code-table td { padding: 0; vertical-align: top; } |
| 10 | 10 | .line-num { |
| 11 | - width: 1%; white-space: nowrap; padding: 0 12px; | |
| 11 | + width: 1%; white-space: nowrap; padding: 0 16px; | |
| 12 | 12 | text-align: right; user-select: none; cursor: pointer; |
| 13 | 13 | color: #4b5563; font-size: 0.75rem; line-height: 1.5rem; |
| 14 | + border-right: 1px solid #374151; | |
| 14 | 15 | } |
| 15 | 16 | .line-num:hover { color: #DC394C; } |
| 16 | 17 | .line-num a { color: inherit; text-decoration: none; display: block; } |
| 17 | 18 | .line-code { |
| 18 | - white-space: pre; padding: 0 16px 0 0; | |
| 19 | + white-space: pre; padding: 0 16px; | |
| 19 | 20 | font-size: 0.8125rem; line-height: 1.5rem; |
| 20 | 21 | } |
| 21 | 22 | .line-row:hover { background: rgba(220, 57, 76, 0.05); } |
| 22 | 23 | .line-row:target { background: rgba(220, 57, 76, 0.12); } |
| 23 | 24 | .line-row:target .line-num { color: #DC394C; font-weight: 600; } |
| 24 | 25 |
| --- templates/fossil/code_file.html | |
| +++ templates/fossil/code_file.html | |
| @@ -6,18 +6,19 @@ | |
| 6 | <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> |
| 7 | <style> |
| 8 | .code-table { border-collapse: collapse; width: 100%; } |
| 9 | .code-table td { padding: 0; vertical-align: top; } |
| 10 | .line-num { |
| 11 | width: 1%; white-space: nowrap; padding: 0 12px; |
| 12 | text-align: right; user-select: none; cursor: pointer; |
| 13 | color: #4b5563; font-size: 0.75rem; line-height: 1.5rem; |
| 14 | } |
| 15 | .line-num:hover { color: #DC394C; } |
| 16 | .line-num a { color: inherit; text-decoration: none; display: block; } |
| 17 | .line-code { |
| 18 | white-space: pre; padding: 0 16px 0 0; |
| 19 | font-size: 0.8125rem; line-height: 1.5rem; |
| 20 | } |
| 21 | .line-row:hover { background: rgba(220, 57, 76, 0.05); } |
| 22 | .line-row:target { background: rgba(220, 57, 76, 0.12); } |
| 23 | .line-row:target .line-num { color: #DC394C; font-weight: 600; } |
| 24 |
| --- templates/fossil/code_file.html | |
| +++ templates/fossil/code_file.html | |
| @@ -6,18 +6,19 @@ | |
| 6 | <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> |
| 7 | <style> |
| 8 | .code-table { border-collapse: collapse; width: 100%; } |
| 9 | .code-table td { padding: 0; vertical-align: top; } |
| 10 | .line-num { |
| 11 | width: 1%; white-space: nowrap; padding: 0 16px; |
| 12 | text-align: right; user-select: none; cursor: pointer; |
| 13 | color: #4b5563; font-size: 0.75rem; line-height: 1.5rem; |
| 14 | border-right: 1px solid #374151; |
| 15 | } |
| 16 | .line-num:hover { color: #DC394C; } |
| 17 | .line-num a { color: inherit; text-decoration: none; display: block; } |
| 18 | .line-code { |
| 19 | white-space: pre; padding: 0 16px; |
| 20 | font-size: 0.8125rem; line-height: 1.5rem; |
| 21 | } |
| 22 | .line-row:hover { background: rgba(220, 57, 76, 0.05); } |
| 23 | .line-row:target { background: rgba(220, 57, 76, 0.12); } |
| 24 | .line-row:target .line-num { color: #DC394C; font-weight: 600; } |
| 25 |
| --- templates/fossil/ticket_list.html | ||
| +++ templates/fossil/ticket_list.html | ||
| @@ -33,6 +33,23 @@ | ||
| 33 | 33 | hx-push-url="true" /> |
| 34 | 34 | </div> |
| 35 | 35 | </div> |
| 36 | 36 | |
| 37 | 37 | {% include "fossil/partials/ticket_table.html" %} |
| 38 | + | |
| 39 | +{% if has_prev or has_next %} | |
| 40 | +<div class="mt-4 flex items-center justify-between text-sm"> | |
| 41 | + <span class="text-gray-500">{{ total }} ticket{{ total|pluralize }}</span> | |
| 42 | + <div class="flex items-center gap-2"> | |
| 43 | + {% if has_prev %} | |
| 44 | + <a href="{% url 'fossil:tickets' slug=project.slug %}?page={{ page|add:"-1" }}{% if status_filter %}&status={{ status_filter }}{% endif %}" | |
| 45 | + class="rounded-md bg-gray-800 px-3 py-1.5 text-gray-400 hover:text-white border border-gray-700">← Prev</a> | |
| 46 | + {% endif %} | |
| 47 | + <span class="text-gray-500">Page {{ page }}</span> | |
| 48 | + {% if has_next %} | |
| 49 | + <a href="{% url 'fossil:tickets' slug=project.slug %}?page={{ page|add:"1" }}{% if status_filter %}&status={{ status_filter }}{% endif %}" | |
| 50 | + class="rounded-md bg-gray-800 px-3 py-1.5 text-gray-400 hover:text-white border border-gray-700">Next →</a> | |
| 51 | + {% endif %} | |
| 52 | + </div> | |
| 53 | +</div> | |
| 54 | +{% endif %} | |
| 38 | 55 | {% endblock %} |
| 39 | 56 |
| --- templates/fossil/ticket_list.html | |
| +++ templates/fossil/ticket_list.html | |
| @@ -33,6 +33,23 @@ | |
| 33 | hx-push-url="true" /> |
| 34 | </div> |
| 35 | </div> |
| 36 | |
| 37 | {% include "fossil/partials/ticket_table.html" %} |
| 38 | {% endblock %} |
| 39 |
| --- templates/fossil/ticket_list.html | |
| +++ templates/fossil/ticket_list.html | |
| @@ -33,6 +33,23 @@ | |
| 33 | hx-push-url="true" /> |
| 34 | </div> |
| 35 | </div> |
| 36 | |
| 37 | {% include "fossil/partials/ticket_table.html" %} |
| 38 | |
| 39 | {% if has_prev or has_next %} |
| 40 | <div class="mt-4 flex items-center justify-between text-sm"> |
| 41 | <span class="text-gray-500">{{ total }} ticket{{ total|pluralize }}</span> |
| 42 | <div class="flex items-center gap-2"> |
| 43 | {% if has_prev %} |
| 44 | <a href="{% url 'fossil:tickets' slug=project.slug %}?page={{ page|add:"-1" }}{% if status_filter %}&status={{ status_filter }}{% endif %}" |
| 45 | class="rounded-md bg-gray-800 px-3 py-1.5 text-gray-400 hover:text-white border border-gray-700">← Prev</a> |
| 46 | {% endif %} |
| 47 | <span class="text-gray-500">Page {{ page }}</span> |
| 48 | {% if has_next %} |
| 49 | <a href="{% url 'fossil:tickets' slug=project.slug %}?page={{ page|add:"1" }}{% if status_filter %}&status={{ status_filter }}{% endif %}" |
| 50 | class="rounded-md bg-gray-800 px-3 py-1.5 text-gray-400 hover:text-white border border-gray-700">Next →</a> |
| 51 | {% endif %} |
| 52 | </div> |
| 53 | </div> |
| 54 | {% endif %} |
| 55 | {% endblock %} |
| 56 |