feat: Add supervision page to display collection attempts shared with the user

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Ross
2026-04-28 22:18:43 +01:00
co-authored by Copilot
parent 7062723433
commit 5bd1338b5e
6 changed files with 434 additions and 65 deletions
@@ -73,6 +73,50 @@
{% endif %}
</div>
</section>
{# ---- Who can see your results ---- #}
{% if sharing_summary %}
<section class="take-start-card mt-3">
<div class="fw-semibold mb-2 small text-body-secondary text-uppercase" style="letter-spacing:.05em;">Who can see your results</div>
<ul class="list-unstyled mb-0 small">
<li class="mb-1">
<span class="badge bg-secondary me-1">You</span>
Always visible to you.
</li>
{% for u in sharing_summary.always_visible_to %}
<li class="mb-1">
<span class="badge bg-secondary me-1">Author/Marker</span>
{{ u.get_full_name|default:u.username }}
{% if u.email %}<span class="text-muted">&lt;{{ u.email }}&gt;</span>{% endif %}
</li>
{% endfor %}
{% if sharing_summary.supervisor_always %}
<li class="mb-1">
<span class="badge bg-info text-dark me-1">Supervisor</span>
{% if sharing_summary.supervisor %}
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
(always shared collection setting)
{% else %}
Your supervisor, if one is linked to your profile (collection setting always on).
{% endif %}
</li>
{% elif sharing_summary.supervisor_opt_in %}
<li class="mb-1">
<span class="badge bg-outline-secondary me-1" style="border:1px solid var(--bs-secondary);color:var(--bs-secondary);">Supervisor</span>
{% if sharing_summary.supervisor %}
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
— you can choose to share with them after starting.
{% else %}
You have a supervisor linked but they don't have a login account yet.
{% endif %}
</li>
{% endif %}
{% if not sharing_summary.always_visible_to and not sharing_summary.supervisor_always and not sharing_summary.supervisor_opt_in %}
<li class="text-muted fst-italic">Only you can see your results for this collection.</li>
{% endif %}
</ul>
</section>
{% endif %}
{% else %}
<section class="take-start-card">
<p class="mb-3">
+63 -63
View File
@@ -2,70 +2,70 @@
{% load static %}
{% block content %}
<div class="mb-3">
<h2 class="h4 mb-1">Shared with me</h2>
<p class="text-muted small mb-0">
Collection attempts shared with you as an author, marker, supervisor, or by direct invitation.
</p>
</div>
<div class="mb-3">
<h2 class="h4 mb-1">Shared with me</h2>
<p class="text-muted small mb-0">
Collection attempts shared with you as an author, marker, supervisor, or by direct invitation.
</p>
</div>
{% if attempt_list %}
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>Collection</th>
<th>Learner</th>
<th>Started</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
{% for attempt, collection in attempt_list %}
{% if attempt_list %}
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<td>
{% if collection %}
<strong>{{ collection.name }}</strong>
{% else %}
<span class="text-muted">Unknown collection</span>
{% endif %}
</td>
<td>
{% if attempt.user_user %}
{{ attempt.user_user.get_full_name|default:attempt.user_user.username }}
{% if attempt.user_user.email %}
<br><span class="small text-muted">{{ attempt.user_user.email }}</span>
{% endif %}
{% elif attempt.cid_user %}
CID {{ attempt.cid_user.cid }}
{% if attempt.cid_user.name %}<br><span class="small text-muted">{{ attempt.cid_user.name }}</span>{% endif %}
{% else %}
<span class="text-muted">Unknown</span>
{% endif %}
</td>
<td class="small">{{ attempt.start_time|default:"-" }}</td>
<td>
{% if attempt.completed %}
<span class="badge bg-success">Completed</span>
{% else %}
<span class="badge bg-warning text-dark">In progress</span>
{% endif %}
</td>
<td>
<a class="btn btn-sm btn-outline-primary"
href="{% url 'atlas:collection_shared_attempt_overview' attempt.pk %}">
View attempt
</a>
</td>
<th>Collection</th>
<th>Learner</th>
<th>Started</th>
<th>Status</th>
<th></th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="alert alert-info">
No collection attempts have been shared with you yet.
</div>
{% endif %}
</thead>
<tbody>
{% for attempt, collection in attempt_list %}
<tr>
<td>
{% if collection %}
<strong>{{ collection.name }}</strong>
{% else %}
<span class="text-muted">Unknown collection</span>
{% endif %}
</td>
<td>
{% if attempt.user_user %}
{{ attempt.user_user.get_full_name|default:attempt.user_user.username }}
{% if attempt.user_user.email %}
<br><span class="small text-muted">{{ attempt.user_user.email }}</span>
{% endif %}
{% elif attempt.cid_user %}
CID {{ attempt.cid_user.cid }}
{% if attempt.cid_user.name %}<br><span class="small text-muted">{{ attempt.cid_user.name }}</span>{% endif %}
{% else %}
<span class="text-muted">Unknown</span>
{% endif %}
</td>
<td class="small">{{ attempt.start_time|default:"-" }}</td>
<td>
{% if attempt.completed %}
<span class="badge bg-success">Completed</span>
{% else %}
<span class="badge bg-warning text-dark">In progress</span>
{% endif %}
</td>
<td>
<a class="btn btn-sm btn-outline-primary"
href="{% url 'atlas:collection_shared_attempt_overview' attempt.pk %}">
View attempt
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="alert alert-info">
No collection attempts have been shared with you yet.
</div>
{% endif %}
{% endblock %}
+136
View File
@@ -0,0 +1,136 @@
{% extends 'atlas/exams.html' %}
{% load static %}
{% block content %}
<div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3">
<div>
<h2 class="h4 mb-1">Supervision</h2>
<p class="text-muted small mb-0">
Collection attempts shared with you as author, marker, supervisor or by direct invitation.
<strong>{{ total_attempts }}</strong> attempt{{ total_attempts|pluralize }} found.
</p>
</div>
</div>
{# ---- Filter / group toolbar ---- #}
<form method="get" class="row g-2 align-items-end mb-4">
<div class="col-12 col-md-auto">
<label class="form-label small mb-1">Group by</label>
<div class="btn-group d-flex" role="group">
<a href="?group_by=user&date_from={{ date_from }}&date_to={{ date_to }}"
class="btn btn-sm {% if group_by == 'user' %}btn-primary{% else %}btn-outline-secondary{% endif %}">
By learner
</a>
<a href="?group_by=collection&date_from={{ date_from }}&date_to={{ date_to }}"
class="btn btn-sm {% if group_by == 'collection' %}btn-primary{% else %}btn-outline-secondary{% endif %}">
By collection
</a>
</div>
</div>
<div class="col-12 col-md-auto">
<label class="form-label small mb-1" for="date_from">From</label>
<input type="date" id="date_from" name="date_from" class="form-control form-control-sm"
value="{{ date_from }}">
</div>
<div class="col-12 col-md-auto">
<label class="form-label small mb-1" for="date_to">To</label>
<input type="date" id="date_to" name="date_to" class="form-control form-control-sm"
value="{{ date_to }}">
</div>
<input type="hidden" name="group_by" value="{{ group_by }}">
<div class="col-12 col-md-auto">
<button type="submit" class="btn btn-sm btn-outline-primary">Apply filter</button>
<a href="{% url 'atlas:collection_supervision' %}" class="btn btn-sm btn-outline-secondary ms-1">Clear</a>
</div>
</form>
{# ---- Grouped results ---- #}
{% if groups %}
{% for group_label, attempt_rows in groups %}
<div class="mb-4">
<h5 class="h6 fw-semibold border-bottom pb-1 mb-2">
{% if group_by == 'user' %}
<i class="bi bi-person me-1" aria-hidden="true"></i>
{% else %}
<i class="bi bi-collection me-1" aria-hidden="true"></i>
{% endif %}
{{ group_label }}
<span class="badge bg-secondary fw-normal ms-1">{{ attempt_rows|length }} attempt{{ attempt_rows|length|pluralize }}</span>
</h5>
<div class="table-responsive">
<table class="table table-hover table-sm align-middle mb-0">
<thead class="table-dark">
<tr>
{% if group_by == 'user' %}
<th>Collection</th>
{% else %}
<th>Learner</th>
{% endif %}
<th>Started</th>
<th>Ended</th>
<th>Status</th>
<th>Progress</th>
<th></th>
</tr>
</thead>
<tbody>
{% for attempt, collection in attempt_rows %}
<tr>
{% if group_by == 'user' %}
<td>
{% if collection %}
{{ collection.name }}
{% else %}
<span class="text-muted">Unknown</span>
{% endif %}
</td>
{% else %}
<td>
{% if attempt.user_user %}
{{ attempt.user_user.get_full_name|default:attempt.user_user.username }}
{% if attempt.user_user.email %}
<br><span class="text-muted small">{{ attempt.user_user.email }}</span>
{% endif %}
{% elif attempt.cid_user %}
CID {{ attempt.cid_user.cid }}
{% if attempt.cid_user.name %}<br><span class="text-muted small">{{ attempt.cid_user.name }}</span>{% endif %}
{% else %}
<span class="text-muted">Unknown</span>
{% endif %}
</td>
{% endif %}
<td class="small text-nowrap">{{ attempt.start_time|default:"-" }}</td>
<td class="small text-nowrap">{{ attempt.end_time|default:"-" }}</td>
<td>
{% if attempt.completed %}
<span class="badge bg-success">Completed</span>
{% else %}
<span class="badge bg-warning text-dark">In progress</span>
{% endif %}
</td>
<td>
{% if attempt.user_user_id %}
<a class="btn btn-sm btn-outline-primary"
href="{% url 'atlas:collection_history_user' exam_id=collection.pk user_pk=attempt.user_user_id %}">
View attempt
</a>
{% else %}
<a class="btn btn-sm btn-outline-primary"
href="{% url 'atlas:collection_shared_attempt_overview' attempt.pk %}">
View attempt
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
{% else %}
<div class="alert alert-info">
No collection attempts have been shared with you yet. Try adjusting the date filter.
</div>
{% endif %}
{% endblock %}