Refactor exam overview template for improved layout and accessibility, adding alerts for JSON status and user group requirements.
This commit is contained in:
@@ -1,62 +1,97 @@
|
|||||||
{% include "generic/exam_link_headers.html" %}
|
{% include "generic/exam_link_headers.html" %}
|
||||||
<h1>Exam: {{ exam }}</h1>
|
|
||||||
|
|
||||||
|
<div class="container-fluid mb-3">
|
||||||
|
<div class="row align-items-start">
|
||||||
|
<div class="col-12 col-md-8">
|
||||||
|
<h1 class="h4 mb-1">Exam: {{ exam }}</h1>
|
||||||
{% include 'exam_notes.html' %}
|
{% include 'exam_notes.html' %}
|
||||||
|
|
||||||
|
|
||||||
{% if exam.examcollection %}
|
{% if exam.examcollection %}
|
||||||
<div>This exam is part of the collection: <a href="{{ exam.examcollection.get_absolute_url }}">{{ exam.examcollection }}</a></div>
|
<div class="mb-2">Part of collection: <a href="{{ exam.examcollection.get_absolute_url }}">{{ exam.examcollection }}</a></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% if exam.recreate_json %}
|
{% if exam.recreate_json %}
|
||||||
<div class="alert alert-warning" role="alert">
|
<div class="alert alert-warning" role="alert">
|
||||||
Exam JSON may be out of date.
|
Exam JSON may be out of date. <a href="{% url exam.get_app_name|add:':exam_json_recreate' pk=exam.pk %}">Force refresh</a>
|
||||||
|
|
||||||
<a href="{% url exam.get_app_name|add:':exam_json_recreate' pk=exam.pk %}">Click here to force refresh</a>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if exam.exam_mode and not exam.exam_open_access %}
|
||||||
{% if exam.exam_mode %}
|
|
||||||
{% if exam.exam_open_access %}
|
|
||||||
{% else %}
|
|
||||||
{% if not exam.cid_user_groups.count and not exam.user_user_groups.count %}
|
{% if not exam.cid_user_groups.count and not exam.user_user_groups.count %}
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
This exam does not have any user / cid groups added.
|
This exam does not have any user / cid groups added.
|
||||||
</div>
|
</div>
|
||||||
{% if not candidate_count.0 and not candidate_count.1 %}
|
{% if not candidate_count.0 and not candidate_count.1 %}
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">This exam does not have any candidates.</div>
|
||||||
This exam does not have any candidates.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% if exam.archive %}
|
{% if exam.archive %}
|
||||||
<div class="alert alert-info" role="alert">
|
<div class="alert alert-info" role="alert">This exam is archived. Results and submitted answers will not be available to candidates (supervisors can still view).</div>
|
||||||
This exam is archived. Results and submitted answers will not be available to candidates. They can still be viewed by supervisors.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
This exam has {{question_number}} questions.
|
<div class="mt-2 small text-muted">
|
||||||
<span title="Time per question: {% widthratio exam.time_limit question_number 1 %} seconds">Time limit: {{exam.time_limit}} seconds [{{exam.get_time_limit}}]
|
This exam has <strong>{{ question_number }}</strong> questions •
|
||||||
<i class="bi bi-info-circle"></i>
|
Time limit: <strong>{{ exam.time_limit }}</strong> seconds (<span title="Time per question: {% widthratio exam.time_limit question_number 1 %} seconds">per question</span>)
|
||||||
</span>.
|
</div>
|
||||||
Exam mode: {{ exam.exam_mode }}<br />
|
|
||||||
|
|
||||||
|
<div class="mt-2">
|
||||||
|
Exam mode: <strong>{{ exam.exam_mode }}</strong>
|
||||||
{% if exam.exam_mode %}
|
{% if exam.exam_mode %}
|
||||||
{% if exam.exam_open_access %}
|
{% if exam.exam_open_access %}
|
||||||
This exam is available to all registered users.<br />
|
<div class="small text-muted">Available to all registered users.</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
Cid candidates: <a href="{{exam.get_cid_edit_url}}">{{candidate_count.0}}</a>, User candidates: <a href="{{exam.get_user_edit_url}}">{{candidate_count.1}}</a><br />
|
<div class="small">Cid candidates: <a href="{{exam.get_cid_edit_url}}">{{candidate_count.0}}</a>, User candidates: <a href="{{exam.get_user_edit_url}}">{{candidate_count.1}}</a></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endif %}
|
<div class="col-12 col-md-4">
|
||||||
<div class="mt-3">
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-2">
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
Open access:
|
||||||
|
<div class="fw-bold">{{ exam.open_access }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-end">
|
||||||
|
{% include "generic/partials/exams/exam_status.html#exam-active" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 small text-muted">
|
||||||
|
{% if exam.start_date %}Start: {{ exam.start_date }}{% endif %}
|
||||||
|
{% if exam.end_date %}/ End: {{ exam.end_date }}{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-2">
|
||||||
|
<div class="small">Markers:</div>
|
||||||
|
<div class="mt-1">
|
||||||
|
{% for marker in exam.markers.all %}
|
||||||
|
<span class="d-inline-block small me-1">{{ marker }}</span>{% if not forloop.last %},{% endif %}
|
||||||
|
{% empty %}
|
||||||
|
<div class="small text-muted">No additional markers.</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-2 small">
|
||||||
|
Supervisor visible: <strong>{{ exam.results_supervisor_visible }}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header p-2">
|
<div class="card-header p-2">
|
||||||
<a class="d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#open-access-bulk" role="button" aria-expanded="false" aria-controls="open-access-bulk">
|
<a class="d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#open-access-bulk" role="button" aria-expanded="false" aria-controls="open-access-bulk">
|
||||||
@@ -66,14 +101,14 @@ Exam mode: {{ exam.exam_mode }}<br />
|
|||||||
</div>
|
</div>
|
||||||
<div class="collapse" id="open-access-bulk">
|
<div class="collapse" id="open-access-bulk">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form hx-post="{% url 'generic:generic_exam_set_open_access' %}" hx-target="#action-result" hx-swap="innerHTML">
|
<form hx-post="{% url 'generic:generic_exam_set_open_access' %}" hx-target="#action-result" hx-swap="innerHTML" class="row g-2 align-items-center">
|
||||||
<input type="hidden" name="type" value="sbas" />
|
<input type="hidden" name="type" value="sbas" />
|
||||||
<input type="hidden" name="exam_id" value="{{ exam.pk }}" />
|
<input type="hidden" name="exam_id" value="{{ exam.pk }}" />
|
||||||
<div class="mb-2 small text-muted">Select questions on the list above (checkboxes) then click one of the actions below.</div>
|
<div class="col-12 col-md-8 small text-muted">Select questions on the list above (checkboxes) then click one of the actions below.</div>
|
||||||
<div class="d-flex gap-2">
|
<div class="col-12 col-md-4 d-flex gap-2 justify-content-md-end">
|
||||||
<button class="btn btn-sm btn-outline-success" type="submit" name="set_open_access" value="true" hx-include="input[name='selection']:checked">Set Open Access = True</button>
|
<button class="btn btn-sm btn-outline-success" type="submit" name="set_open_access" value="true" hx-include="input[name='selection']:checked">Set Open Access = True</button>
|
||||||
<button class="btn btn-sm btn-outline-danger" type="submit" name="set_open_access" value="false" hx-include="input[name='selection']:checked">Set Open Access = False</button>
|
<button class="btn btn-sm btn-outline-danger" type="submit" name="set_open_access" value="false" hx-include="input[name='selection']:checked">Set Open Access = False</button>
|
||||||
<button class="btn btn-sm btn-secondary" type="button" onclick="document.querySelector('#open-access-bulk').classList.remove('show');">Close</button>
|
<button class="btn btn-sm btn-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#open-access-bulk">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div id="action-result" class="mt-2"></div>
|
<div id="action-result" class="mt-2"></div>
|
||||||
@@ -81,81 +116,51 @@ Exam mode: {{ exam.exam_mode }}<br />
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
Markers:
|
|
||||||
{% for marker in exam.markers.all %}
|
|
||||||
{{marker}}{% if not forloop.last %},{% endif %}
|
|
||||||
{% empty %}
|
|
||||||
<span title="Only exam authors will be able to mark.">No additional markers.</span>
|
|
||||||
{% endfor %}
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
|
|
||||||
{% if can_edit and exam.exam_mode %}
|
|
||||||
<details class="answer-management">
|
|
||||||
<summary>Answer management</summary>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
<i class="bi bi-exclamation-diamond"></i> Manage answers for this collection. Please note these are <b>permanant</b> and cannot be undone.
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<details>
|
<div class="container-fluid">
|
||||||
<summary>Click here to show management options</summary>
|
<div class="row">
|
||||||
<button title="This will clear all user answers and attempts"
|
<div class="col-12">
|
||||||
|
{% if can_edit and exam.exam_mode %}
|
||||||
|
<div class="card mb-2">
|
||||||
|
<div class="card-body p-2">
|
||||||
|
<details class="mb-0">
|
||||||
|
<summary class="small">Answer management</summary>
|
||||||
|
<div class="mt-2">
|
||||||
|
<div class="alert alert-danger small mb-2">
|
||||||
|
<i class="bi bi-exclamation-diamond"></i> Manage answers for this collection. These actions are permanent.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-sm btn-danger" title="This will clear all user answers and attempts"
|
||||||
hx-post="{% url exam.get_app_name|add:':exam_reset_answers' exam.pk %}"
|
hx-post="{% url exam.get_app_name|add:':exam_reset_answers' exam.pk %}"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-confirm="Are you sure you want to reset all answers? This action cannot be undone."
|
hx-confirm="Are you sure you want to reset all answers? This action cannot be undone.">Reset all answers</button>
|
||||||
>Reset all answers</button>
|
</div>
|
||||||
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</details>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
Open access: {{ exam.open_access }}<br />
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
{% if exam.start_date %}
|
|
||||||
Start date: {{ exam.start_date }}
|
|
||||||
{% endif %}
|
|
||||||
{% if exam.end_date %}
|
|
||||||
/ End date: {{ exam.end_date }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% include "generic/partials/exams/exam_status.html#exam-active" %}
|
|
||||||
{% if exam.exam_mode %}
|
|
||||||
|
|
||||||
{% include "generic/partials/exams/exam_status.html#publish-results" %}
|
|
||||||
{% if exam.get_app_name == "anatomy" or exam.get_app_name == "longs" %}
|
|
||||||
<p><a href="{% url exam.get_app_name|add:':mark_overview' pk=exam.pk %}"><button>Mark exam</button></a></p>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% if exam.examcollection %}
|
{% if exam.examcollection %}
|
||||||
Exam Collection: <a href="{{ exam.examcollection.get_absolute_url }}">{{ exam.examcollection }}</a> <br/>
|
<div class="small">Exam Collection: <a href="{{ exam.examcollection.get_absolute_url }}">{{ exam.examcollection }}</a></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Author(s): {% for author in exam.author.all %}
|
<div class="small mt-1">Author(s): {% for author in exam.author.all %}{{ author }}{% if not forloop.last %}, {% endif %}{% endfor %}</div>
|
||||||
{{ author }}{% if not forloop.last %}, {% endif %}
|
</div>
|
||||||
{% endfor %}<br/>
|
<div class="col-12 col-md-6 text-md-end small mt-2 mt-md-0">
|
||||||
<span title="If true the results from this exam will be visible to supervisors automatically. If false the trainee will have to manually approve access.">Supervisor visible: {{exam.results_supervisor_visible}}</span><br/>
|
<span title="If true the results from this exam will be visible to supervisors automatically.">Supervisor visible: {{ exam.results_supervisor_visible }}</span>
|
||||||
|
</div>
|
||||||
<details>
|
</div>
|
||||||
<summary>Extra</summary>
|
</div>
|
||||||
Occasionally the order of questions can get out of sync. If you are exeriancing issues with the order of questions you can reset the order here.
|
|
||||||
<button title="This will clear all user answers and attempts"
|
|
||||||
hx-post="{% url exam.get_app_name|add:':order_questions' exam.pk %}"
|
|
||||||
hx-swap="outerHTML"
|
|
||||||
>Order questions</button>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
<style>
|
<style>
|
||||||
.answer-management[open] {
|
.answer-management[open] { border: 1px dashed lightgrey; }
|
||||||
border: 1px dashed lightgrey;
|
|
||||||
border-top: 1px dotted lightgrey;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
{% endblock css %}
|
{% endblock css %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user