Add grade information to user search results and enhance user addition functionality

This commit is contained in:
Ross
2025-11-12 21:59:20 +00:00
parent d8055a509c
commit 2e551d411a
3 changed files with 56 additions and 12 deletions
+28 -4
View File
@@ -658,7 +658,29 @@ class UserUserGroupForm(ModelForm):
timeout = setTimeout(() => fetchResults(search.value), 50);
}});
window.addUserToField = function(fieldName, id, text) {{
// fieldName for this widget instance
const widgetFieldName = '{self.name}';
// Add button click delegation: results list buttons have data attributes
results.addEventListener('click', function(e) {{
const btn = e.target.closest('.user-add-btn');
if (!btn) return;
const id = btn.getAttribute('data-user-id');
const text = btn.getAttribute('data-user-text') || btn.textContent.trim();
const grade = btn.getAttribute('data-user-grade') || '';
addUserToField(widgetFieldName, id, text, grade);
}});
// Wire up the "Add all results" button if present
const addAllBtn = results.parentElement.querySelector('.user-add-all-btn');
if (addAllBtn) {
addAllBtn.addEventListener('click', function(e) {{
e.preventDefault();
addAllFromResults(widgetFieldName);
}});
}
window.addUserToField = function(fieldName, id, text, grade) {{
const sel = document.getElementById('id_' + fieldName);
if (!sel) return;
// prevent duplicate
@@ -666,11 +688,12 @@ class UserUserGroupForm(ModelForm):
const opt = document.createElement('option'); opt.value = id; opt.selected = true; opt.text = text;
sel.appendChild(opt);
// add to visible list
// add to visible list (include grade if provided)
const li = document.createElement('li');
li.className = 'list-group-item d-flex justify-content-between align-items-center';
li.id = 'selected_user_' + fieldName + '_' + id;
const span = document.createElement('span'); span.innerHTML = text;
const span = document.createElement('span');
span.innerHTML = text + (grade ? ' <small class="text-muted ms-2">' + grade + '</small>' : '');
const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'btn btn-sm btn-outline-danger ms-2'; btn.innerText = 'Remove';
btn.addEventListener('click', function() {{ removeUserFromField(fieldName, id); }});
li.appendChild(span); li.appendChild(btn);
@@ -692,7 +715,8 @@ class UserUserGroupForm(ModelForm):
items.forEach(function(it) {{
const id = it.getAttribute('data-user-id');
const text = it.getAttribute('data-user-text') || it.textContent.trim();
addUserToField(fieldName, id, text);
const grade = it.getAttribute('data-user-grade') || '';
addUserToField(fieldName, id, text, grade);
}});
}}
}})();
@@ -1,17 +1,22 @@
{% if results %}
<ul class="list-unstyled mb-0" id="user_search_results_list_{{ field }}">
{% for item in results %}
<li class="py-1 d-flex justify-content-between align-items-center" data-user-id="{{ item.id }}" data-user-text="{{ item.text|escapejs }}">
<div class="flex-grow-1">{{ item.text|escape }}</div>
<li class="py-1 d-flex justify-content-between align-items-center" data-user-id="{{ item.id }}" data-user-text="{{ item.text|escapejs }}" data-user-grade="{{ item.grade|default_if_none:''|escapejs }}">
<div class="flex-grow-1">
{{ item.text|escape }}
{% if item.grade %}
<small class="text-muted ms-2">{{ item.grade|escape }}</small>
{% endif %}
</div>
<div>
<button type="button" class="btn btn-sm btn-primary" onclick="addUserToField('{{ field }}', {{ item.id }}, '{{ item.text|escapejs }}')">Add</button>
<button type="button" class="btn btn-sm btn-primary user-add-btn" data-user-id="{{ item.id }}" data-user-text="{{ item.text|escapejs }}" data-user-grade="{{ item.grade|default_if_none:''|escapejs }}">Add</button>
</div>
</li>
{% endfor %}
</ul>
{% if results %}
<div class="mt-2 text-end">
<button type="button" class="btn btn-sm btn-outline-success" onclick="addAllFromResults('{{ field }}')">Add all results</button>
<button type="button" class="btn btn-sm btn-outline-success user-add-all-btn" data-field="{{ field }}">Add all results</button>
</div>
{% endif %}
{% else %}
+19 -4
View File
@@ -6017,10 +6017,25 @@ def user_search_widget(request):
limit = 50 if q in ("*", "%") or q_raw in ("*", "%") else 10
users_qs = users_qs.order_by("last_name", "first_name")[:limit]
results = [
{"id": u.pk, "text": f"{u.get_full_name() or u.username} - {u.email or ''}"}
for u in users_qs
]
results = []
for u in users_qs:
grade = ""
try:
up = getattr(u, "userprofile", None)
if up and getattr(up, "grade", None):
# grade may be a FK object or a simple string depending on model
g = up.grade
grade = getattr(g, "name", str(g)) if g is not None else ""
except Exception:
grade = ""
results.append(
{
"id": u.pk,
"text": f"{u.get_full_name() or u.username} - {u.email or ''}",
"grade": grade,
}
)
return render(
request,