Add logging for bulk delete request and update button for selected questions deletion
This commit is contained in:
@@ -160,6 +160,8 @@ def bulk_delete_questions(request):
|
|||||||
if request.method != "POST":
|
if request.method != "POST":
|
||||||
return HttpResponse(status=405)
|
return HttpResponse(status=405)
|
||||||
|
|
||||||
|
logger.debug(f"bulk_delete_questions called with POST: {request.POST}")
|
||||||
|
|
||||||
app = request.POST.get("app")
|
app = request.POST.get("app")
|
||||||
|
|
||||||
# Accept different submission patterns: checkboxes may be sent as 'selection' or 'selected'
|
# Accept different submission patterns: checkboxes may be sent as 'selection' or 'selected'
|
||||||
|
|||||||
@@ -18,15 +18,15 @@
|
|||||||
</form>
|
</form>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
<form id="bulk-delete-form" method="post" action="{% url 'generic:bulk_delete_questions' %}" hx-post="{% url 'generic:bulk_delete_questions' %}" hx-target="#bulk-delete-result" hx-swap="innerHTML">
|
|
||||||
{% render_table table %}
|
{% render_table table %}
|
||||||
|
|
||||||
{% csrf_token %}
|
<button id="delete-selected-btn" class="btn btn-danger btn-sm mt-2"
|
||||||
<input type="hidden" name="app" value="{{ app_name }}">
|
hx-post="{% url 'generic:bulk_delete_questions' %}"
|
||||||
<input type="hidden" name="selected" id="bulk-selected-input" value="">
|
hx-include="[name='selection']:checked" hx-vals='{"app":"{{ app_name|escapejs }}"}'
|
||||||
<button id="button-bulk-delete" class="btn btn-danger btn-sm" type="submit">Delete selected</button>
|
hx-target="#action-result"
|
||||||
<span id="bulk-delete-result" class="ms-2"></span>
|
hx-swap="innerHTML"
|
||||||
</form>
|
hx-confirm="Are you sure you want to delete the selected questions? This action cannot be undone.">
|
||||||
|
Delete selected questions</button>
|
||||||
|
|
||||||
<button id="button-select-add-exam"
|
<button id="button-select-add-exam"
|
||||||
data-exam_json_edit_url="{% url 'generic:generic_exam_json_edit' %}"
|
data-exam_json_edit_url="{% url 'generic:generic_exam_json_edit' %}"
|
||||||
@@ -34,67 +34,6 @@
|
|||||||
data-type={{app_name}} data-csrf="{{ csrf_token}}">Add selected questions to
|
data-type={{app_name}} data-csrf="{{ csrf_token}}">Add selected questions to
|
||||||
exam</button>
|
exam</button>
|
||||||
|
|
||||||
{% endblock %}
|
<div id="action-result" class="mt-2"></div>
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
<script>
|
|
||||||
// When the user submits the bulk-delete form, gather selected checkboxes from the table
|
|
||||||
document.getElementById('bulk-delete-form').addEventListener('submit', function(e){
|
|
||||||
const selected = [];
|
|
||||||
// Try common patterns: name="selection", name="selection[]", name="selection-<pk>", data-pk, or any checked checkbox inside the table
|
|
||||||
// 1) explicit selection name
|
|
||||||
document.querySelectorAll('input[type=checkbox][name="selection"]:checked, input[type=checkbox][name="selection[]"]:checked').forEach(function(cb){
|
|
||||||
if(cb.value) selected.push(cb.value);
|
|
||||||
else if(cb.dataset && cb.dataset.pk) selected.push(cb.dataset.pk);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2) inputs with name like selection-<pk> or selection_<pk>
|
|
||||||
document.querySelectorAll('input[type=checkbox]').forEach(function(cb){
|
|
||||||
if(!cb.checked) return;
|
|
||||||
const n = cb.getAttribute('name') || '';
|
|
||||||
if(n.startsWith('selection-') || n.startsWith('selection_')){
|
|
||||||
// try extract trailing number
|
|
||||||
const m = n.match(/selection[-_](\d+)/);
|
|
||||||
if(m && m[1]){
|
|
||||||
selected.push(m[1]);
|
|
||||||
} else if(cb.value){
|
|
||||||
selected.push(cb.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 3) fallback: any checked checkbox inside the rendered table
|
|
||||||
if(cb.closest('table') && cb.checked && cb.value){
|
|
||||||
selected.push(cb.value);
|
|
||||||
}
|
|
||||||
// 4) data-pk attribute
|
|
||||||
if(cb.checked && cb.dataset && cb.dataset.pk){
|
|
||||||
selected.push(cb.dataset.pk);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// fallback: django-tables2 renders checkboxes with accessor name 'selection' and value
|
|
||||||
if(selected.length === 0){
|
|
||||||
// try to find inputs inside table
|
|
||||||
document.querySelectorAll('table input[type=checkbox]').forEach(function(cb){
|
|
||||||
if(cb.checked && cb.value) selected.push(cb.value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// dedupe
|
|
||||||
const uniq = Array.from(new Set(selected.map(String)));
|
|
||||||
console.log('Bulk delete selected ids:', uniq);
|
|
||||||
document.getElementById('bulk-selected-input').value = uniq.join(',');
|
|
||||||
// Confirm with the user before submitting
|
|
||||||
const count = uniq.length;
|
|
||||||
if(count === 0){
|
|
||||||
// nothing selected: prevent submit and show alert
|
|
||||||
e.preventDefault();
|
|
||||||
alert('No items selected for deletion.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const ok = confirm(`Delete ${count} selected question${count === 1 ? '' : 's'}? This cannot be undone.`);
|
|
||||||
if(!ok){
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// allow HTMX to submit
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user