Add user search widget to exam_users_edit.html for adding arbitrary users
This commit is contained in:
@@ -11,18 +11,20 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="small text-muted mt-1">This exam is not associated with any user groups. <a href="{% url exam.app_name|add:':exam_groups_edit' exam.pk %}">Edit and add a group</a> to enable user management.</div>
|
||||
<div class="small text-muted mt-1">This exam is not associated with any user groups. <a href="{% url app_name|add:':exam_groups_edit' exam.pk %}">Edit and add a group</a> to enable user management.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
{% if current_user_users or available_user_users %}
|
||||
<button class="btn btn-sm btn-outline-light toggle-all-btn" data-bulk-url="{% url exam.app_name|add:':exam_user_bulk_edit' exam.pk %}">Toggle all</button>
|
||||
<button class="btn btn-sm btn-outline-light toggle-all-btn" data-bulk-url="{% url app_name|add:':exam_user_bulk_edit' exam.pk %}">Toggle all</button>
|
||||
{% endif %}
|
||||
<button class="btn btn-sm btn-outline-success add-all-btn" data-bulk-url="{% url exam.app_name|add:':exam_user_bulk_edit' exam.pk %}">Add all</button>
|
||||
<button class="btn btn-sm btn-outline-danger remove-all-btn" data-bulk-url="{% url exam.app_name|add:':exam_user_bulk_edit' exam.pk %}">Remove all</button>
|
||||
<button class="btn btn-sm btn-outline-success add-all-btn" data-bulk-url="{% url app_name|add:':exam_user_bulk_edit' exam.pk %}">Add all</button>
|
||||
<button class="btn btn-sm btn-outline-danger remove-all-btn" data-bulk-url="{% url app_name|add:':exam_user_bulk_edit' exam.pk %}">Remove all</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="me-auto small text-muted">Sort by:</div>
|
||||
<div class="btn-group btn-group-sm user-sort-group" role="group" aria-label="Sort">
|
||||
@@ -36,6 +38,22 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Collapsible panel for adding arbitrary users (collapsed by default) -->
|
||||
<div class="mt-3">
|
||||
<p>
|
||||
<a class="btn btn-sm btn-link" data-bs-toggle="collapse" href="#add-arbitrary-users-collapse" role="button" aria-expanded="false" aria-controls="add-arbitrary-users-collapse">Add arbitrary users</a>
|
||||
</p>
|
||||
<div class="collapse" id="add-arbitrary-users-collapse">
|
||||
<div class="card card-body">
|
||||
<label class="form-label small mb-1">Add arbitrary users</label>
|
||||
{{ user_search_widget|default:''|safe }}
|
||||
<div class="mt-2">
|
||||
<button type="button" id="add-selected-users-btn" class="btn btn-sm btn-outline-success">Add selected users</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Mirror the HTMX-enabled behavior used for CID users.
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
@@ -69,12 +87,24 @@
|
||||
.finally(()=>{ if(triggeringButton) setLoading(triggeringButton, false); });
|
||||
}
|
||||
|
||||
const defaultBulkUrl = "{% url exam.app_name|add:':exam_user_bulk_edit' exam.pk %}";
|
||||
const defaultBulkUrl = "{% url app_name|add:':exam_user_bulk_edit' exam.pk %}";
|
||||
document.querySelectorAll('.add-all-btn').forEach(function(btn){ btn.addEventListener('click', function(){ const url = btn.dataset.bulkUrl || defaultBulkUrl; const items = document.querySelectorAll('#user-users-list li:not(.current)'); const pks = Array.from(items).map(i => i.dataset.pk).filter(Boolean).map(Number); if (!pks.length) return; submitBulk(url, pks, true, btn); }); });
|
||||
document.querySelectorAll('.remove-all-btn').forEach(function(btn){ btn.addEventListener('click', function(){ if(!confirm('Remove all selected users from the exam?')) return; const url = btn.dataset.bulkUrl || defaultBulkUrl; const items = document.querySelectorAll('#user-users-list li.current'); const pks = Array.from(items).map(i => i.dataset.pk).filter(Boolean).map(Number); if (!pks.length) return; submitBulk(url, pks, false, btn); }); });
|
||||
|
||||
document.querySelectorAll('.toggle-all-btn').forEach(function(btn){ btn.addEventListener('click', function(){ const url = btn.dataset.bulkUrl || document.querySelector('.add-all-btn')?.dataset.bulkUrl || defaultBulkUrl; const items = Array.from(document.querySelectorAll('#user-users-list li')).map(function(li){ return { pk: Number(li.dataset.pk), add: !li.classList.contains('current') }; }); if (!items.length) return; submitBulk(url, items, null, btn); }); });
|
||||
|
||||
// Handler for adding arbitrary selected users from the search widget
|
||||
const addSelectedBtn = document.getElementById('add-selected-users-btn');
|
||||
if (addSelectedBtn){
|
||||
addSelectedBtn.addEventListener('click', function(){
|
||||
const sel = document.getElementById('id_add_users');
|
||||
if(!sel) return;
|
||||
const pks = Array.from(sel.options).map(o => o.value).filter(Boolean).map(Number);
|
||||
if(!pks.length) return;
|
||||
submitBulk(defaultBulkUrl, pks, true, addSelectedBtn);
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for single-item toggle events to update counts and show toasts
|
||||
document.body.addEventListener('user_toggled', function(evt){ try { const detail = evt.detail || {}; const added = detail.added; if (window.toastr) { if (added) toastr.info('User added to exam'); else toastr.info('User removed from exam'); } const addedEl = document.getElementById('user-count-added'); const availEl = document.getElementById('user-count-available'); if (addedEl && availEl){ let addedCount = parseInt(addedEl.textContent || '0') || 0; let availCount = parseInt(availEl.textContent || '0') || 0; if (added){ addedCount += 1; availCount = Math.max(0, availCount - 1); } else { addedCount = Math.max(0, addedCount - 1); availCount += 1; } addedEl.textContent = String(addedCount); availEl.textContent = String(availCount); } } catch(e){} });
|
||||
|
||||
|
||||
@@ -2419,6 +2419,15 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
"app_name": self.app_name,
|
||||
}
|
||||
|
||||
# Provide a searchable widget to allow adding arbitrary users
|
||||
try:
|
||||
from generic.widgets import UserSearchSelectMultipleWidget
|
||||
|
||||
widget_html = UserSearchSelectMultipleWidget("add_users", []).render()
|
||||
context["user_search_widget"] = mark_safe(widget_html)
|
||||
except Exception:
|
||||
context["user_search_widget"] = ""
|
||||
|
||||
if self.app_name == "atlas":
|
||||
context["collection"] = exam
|
||||
|
||||
|
||||
Reference in New Issue
Block a user