Implement bulk update and delete functionality for exams with HTMX support

This commit is contained in:
Ross
2025-11-06 21:53:35 +00:00
parent 17541b8187
commit 54afa6e6bd
4 changed files with 193 additions and 19 deletions
+46 -19
View File
@@ -1,26 +1,33 @@
{% extends app_name|add:'/base.html' %}
{% block content %}
<h4 class="exam-number-title">{{filter.qs|length}} exams found.</h4>
{% for exam in filter.qs %}
<div class="">
<h1><a href="{% url app_name|add:':exam_overview' pk=exam.pk %}">
{% if exam.exam_mode %}
Exam:
{% else %}
Packet:
{% endif %}
{{ exam }} </a></h1>
<span class="authors">Authors: {{exam.get_authors}}</span>
{% if exam.exam_mode %}
{% if app_name in "rapids longs anatomy" %}
{% if request.user.is_staff %}<a href="{% url app_name|add:':mark_overview' pk=exam.pk %}">Mark answers</a>{% endif %}
{% endif %}
{% if request.user.is_staff %}<a href="{% url app_name|add:':exam_scores_all' pk=exam.pk %}">Scores</a>{% endif %}
{% endif %}
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<button type="button" class="btn btn-sm btn-outline-primary" id="select-all-btn">Select all</button>
<button type="button" class="btn btn-sm btn-outline-secondary" id="clear-selection-btn">Clear</button>
</div>
{% endfor %}
<div class="d-flex align-items-center">
<form id="bulk-date-form" hx-post="{% url app_name|add:':exam_bulk_update' %}" hx-target="#exam-list-container" hx-include="#exam-list-container input[name='exam_ids']">
{% for k, v in request.GET.items %}
<input type="hidden" name="{{ k }}" value="{{ v }}" />
{% endfor %}
{% csrf_token %}
<div class="input-group input-group-sm">
<input type="date" class="form-control" name="date" aria-label="Set date">
<button class="btn btn-sm btn-primary" type="submit">Update date</button>
</div>
</form>
<form id="bulk-delete-form" class="ms-2" hx-post="{% url app_name|add:':exam_bulk_delete' %}" hx-target="#exam-list-container" hx-include="#exam-list-container input[name='exam_ids']">
{% for k, v in request.GET.items %}
<input type="hidden" name="{{ k }}" value="{{ v }}" />
{% endfor %}
{% csrf_token %}
<button class="btn btn-sm btn-danger" type="submit" onclick="return confirm('Delete selected exams? This action is irreversible.')">Delete selected</button>
</form>
</div>
</div>
{% include 'generic/partials/_exam_list.html' with filter=filter app_name=app_name %}
{% include "generic/partials/filter_bar.html" with filter=filter app_name=app_name collapse_id="bottom-filter-body" %}
{% endblock %}
@@ -37,3 +44,23 @@
</style>
{% endblock css %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function(){
const selectAllBtn = document.getElementById('select-all-btn');
const clearBtn = document.getElementById('clear-selection-btn');
function setAllCheckboxes(checked){
document.querySelectorAll('#exam-list-container input.exam-select-checkbox').forEach(cb => cb.checked = checked);
}
if(selectAllBtn){
selectAllBtn.addEventListener('click', function(){ setAllCheckboxes(true); });
}
if(clearBtn){
clearBtn.addEventListener('click', function(){ setAllCheckboxes(false); });
}
});
</script>
{% endblock %}
@@ -0,0 +1,26 @@
{# Partial: list of exams used by HTMX bulk actions #}
<div id="exam-list-container">
<h4 class="exam-number-title">{{ filter.qs|length }} exams found.</h4>
{% for exam in filter.qs %}
<div class="mb-2" id="exam-{{ exam.pk }}">
<div class="d-flex align-items-start">
<div class="form-check me-2">
<input class="form-check-input exam-select-checkbox" type="checkbox" name="exam_ids" value="{{ exam.pk }}" id="select-exam-{{ exam.pk }}">
</div>
<div>
<h5 class="mb-0"><a href="{% url app_name|add:':exam_overview' pk=exam.pk %}">
{% if exam.exam_mode %}Exam:{% else %}Packet:{% endif %} {{ exam }}
</a></h5>
<small class="text-muted">Authors: {{ exam.get_authors }}</small>
{% if exam.exam_mode %}
{% if app_name in "rapids longs anatomy" %}
{% if request.user.is_staff %}<a href="{% url app_name|add:':mark_overview' pk=exam.pk %}">Mark answers</a>{% endif %}
{% endif %}
{% if request.user.is_staff %}<a href="{% url app_name|add:':exam_scores_all' pk=exam.pk %}">Scores</a>{% endif %}
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>