From 378d784435628eb2b2c88ac0ea0829d97d06125b Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 5 Jan 2026 11:30:53 +0000 Subject: [PATCH] Enhance submitted candidates display by adding dynamic exam status indicators and improving badge tooltip functionality for better user feedback. --- generic/templates/generic/exam_cids.html | 55 +++++++++---------- .../partials/exam_cids_submitted_list.html | 8 +-- generic/views.py | 19 +++++++ 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/generic/templates/generic/exam_cids.html b/generic/templates/generic/exam_cids.html index 5703fd34..bf48ce6a 100644 --- a/generic/templates/generic/exam_cids.html +++ b/generic/templates/generic/exam_cids.html @@ -174,52 +174,47 @@ }catch(e){ console.error('highlightSubmitted collect error', e); } }); - // Add badges for CID list items + // Helper to ensure a single badge exists inside an li and update its tooltip + function ensureSubmittedBadge(li, title){ + let b = li.querySelector('.submitted-badge'); + if(!b){ + b = document.createElement('span'); + b.className = 'submitted-badge badge bg-success ms-2'; + b.textContent = 'Submitted'; + li.appendChild(b); + } + if(title){ + b.setAttribute('title', title); + b.setAttribute('data-bs-toggle', 'tooltip'); + } + return b; + } + + // Add/update badges for CID list items if(submittedCids.size){ document.querySelectorAll('#cid-list .list-group-item').forEach(function(li){ try{ const link = li.querySelector && li.querySelector('.cid-link'); const text = (link && link.textContent) ? link.textContent.trim() : (li.textContent||'').trim(); - if(submittedCids.has(text) && !li.querySelector('.submitted-badge')){ + if(submittedCids.has(text)){ const info = submittedCids.get(text) || {first:'', last:''}; - const badge = document.createElement('span'); - badge.className = 'submitted-badge badge bg-success ms-2'; - badge.textContent = 'Submitted'; - if(info.first || info.last){ - const title = `Submitted\nFirst: ${info.first}\nLast: ${info.last}`; - badge.setAttribute('title', title); - badge.setAttribute('data-bs-toggle', 'tooltip'); - } - if(link && link.parentNode){ - link.parentNode.appendChild(badge); - } else { - li.appendChild(badge); - } + const title = (info.first || info.last) ? `Submitted\nFirst: ${info.first}\nLast: ${info.last}` : ''; + ensureSubmittedBadge(li, title); } }catch(e){ console.error('highlightSubmitted CID item error', e); } }); } - // Add badges for User list items + // Add/update badges for User list items if(submittedUsers.size){ document.querySelectorAll('#user-list .list-group-item').forEach(function(li){ try{ const txt = (li.textContent||'').trim(); - for(const user of submittedUsers){ + for(const user of submittedUsers.keys()){ if(txt.indexOf(user) !== -1){ - if(!li.querySelector('.submitted-badge')){ - const info = submittedUsers.get(user) || {first:'', last:''}; - const badge = document.createElement('span'); - badge.className = 'submitted-badge badge bg-success ms-2'; - badge.textContent = 'Submitted'; - if(info.first || info.last){ - const title = `Submitted\nFirst: ${info.first}\nLast: ${info.last}`; - badge.setAttribute('title', title); - badge.setAttribute('data-bs-toggle', 'tooltip'); - } - const nameEl = li.querySelector('.fw-bold') || li.querySelector('a') || li; - nameEl.appendChild(badge); - } + const info = submittedUsers.get(user) || {first:'', last:''}; + const title = (info.first || info.last) ? `Submitted\nFirst: ${info.first}\nLast: ${info.last}` : ''; + ensureSubmittedBadge(li, title); break; } } diff --git a/generic/templates/generic/partials/exam_cids_submitted_list.html b/generic/templates/generic/partials/exam_cids_submitted_list.html index 5f4914f0..f6aa259a 100644 --- a/generic/templates/generic/partials/exam_cids_submitted_list.html +++ b/generic/templates/generic/partials/exam_cids_submitted_list.html @@ -23,11 +23,11 @@ {% for user_data in user_exam_data %} - - {{ user_data.cid_user }} + + {{ user_data.cid_user }}{% if not user_data.in_exam %} Not added{% endif %} {{ user_data.user_user }} - {{ user_data.start_time }} - {{ user_data.end_time }} + {{ user_data.start_time }} + {{ user_data.end_time }}
diff --git a/generic/views.py b/generic/views.py index ca0a0d21..f4c92a23 100644 --- a/generic/views.py +++ b/generic/views.py @@ -2347,6 +2347,25 @@ class ExamViews(View, LoginRequiredMixin): .order_by("start_time") ) + # Determine which submitted entries correspond to candidates/users + # that are actually added to the exam so we can highlight those that + # are not. Collect valid IDs once to avoid per-row queries. + valid_cid_pks = set(exam.valid_cid_users.values_list("pk", flat=True)) + valid_user_pks = set(exam.valid_user_users.values_list("pk", flat=True)) + + for ue in user_exam_data: + in_exam = False + try: + if ue.cid_user_id and ue.cid_user_id in valid_cid_pks: + in_exam = True + if ue.user_user_id and ue.user_user_id in valid_user_pks: + in_exam = True + except Exception: + in_exam = False + + # Attach a dynamic attribute the template can read + setattr(ue, "in_exam", in_exam) + return render( request, "generic/partials/exam_cids_submitted_list.html",