Compare commits
4
Commits
a1aba7836a
...
e407326c25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e407326c25 | ||
|
|
0d8177f0b4 | ||
|
|
3312f3058a | ||
|
|
478dcb7217 |
+20
-1
@@ -142,6 +142,25 @@ class CaseCollectionForm(ModelForm):
|
|||||||
ModelForm.__init__(self, *args, **kwargs)
|
ModelForm.__init__(self, *args, **kwargs)
|
||||||
super(CaseCollectionForm, self).__init__(*args, **kwargs)
|
super(CaseCollectionForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Render collection_type as radio buttons and ensure it appears near the top
|
||||||
|
if "collection_type" in self.fields:
|
||||||
|
# Replace the model field with an explicit ChoiceField that uses RadioSelect
|
||||||
|
original = self.fields["collection_type"]
|
||||||
|
choices = getattr(original, "choices", ())
|
||||||
|
initial = original.initial if hasattr(original, "initial") else None
|
||||||
|
required = original.required
|
||||||
|
label = original.label
|
||||||
|
widget = RadioSelect(attrs={"class": "btn-check"})
|
||||||
|
# assign custom template for rendering as button group
|
||||||
|
#widget.template_name = "widgets/radioselect_buttons.html"
|
||||||
|
self.fields["collection_type"] = forms.ChoiceField(
|
||||||
|
choices=choices,
|
||||||
|
widget=widget,
|
||||||
|
initial=initial,
|
||||||
|
required=required,
|
||||||
|
label=label,
|
||||||
|
)
|
||||||
|
|
||||||
# Identify show_ fields
|
# Identify show_ fields
|
||||||
show_fields = [f for f in self.fields if f.startswith("show_")]
|
show_fields = [f for f in self.fields if f.startswith("show_")]
|
||||||
show_pre_fields = [f for f in show_fields if f.endswith("_pre")]
|
show_pre_fields = [f for f in show_fields if f.endswith("_pre")]
|
||||||
@@ -187,6 +206,7 @@ class CaseCollectionForm(ModelForm):
|
|||||||
Fieldset(
|
Fieldset(
|
||||||
"Collection Details",
|
"Collection Details",
|
||||||
"name",
|
"name",
|
||||||
|
Field("collection_type", css_class="mb-2"),
|
||||||
Fieldset(
|
Fieldset(
|
||||||
"Dates",
|
"Dates",
|
||||||
"restrict_to_dates",
|
"restrict_to_dates",
|
||||||
@@ -214,7 +234,6 @@ class CaseCollectionForm(ModelForm):
|
|||||||
"exam_mode",
|
"exam_mode",
|
||||||
"self_review",
|
"self_review",
|
||||||
"feedback_once_collection_complete",
|
"feedback_once_collection_complete",
|
||||||
"collection_type",
|
|
||||||
"viewer_mode",
|
"viewer_mode",
|
||||||
"question_time_limit",
|
"question_time_limit",
|
||||||
"prerequisites",
|
"prerequisites",
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-11-15 22:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('atlas', '0083_resource_created_date_resource_modified_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='resource',
|
||||||
|
name='open_access',
|
||||||
|
field=models.BooleanField(default=True, help_text='If true the resource is available to all users, otherwise only in the context of cases.'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -3,6 +3,40 @@
|
|||||||
{% load crispy_forms_tags %}
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
|
<style>
|
||||||
|
/* Turn the existing form-check radio markup into horizontal button-like radios */
|
||||||
|
#div_id_collection_type .form-check { display: inline-block; margin-right: .5rem; }
|
||||||
|
#div_id_collection_type .form-check-input {
|
||||||
|
/* visually hide the native radio but keep it focusable */
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0,0,0,0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
#div_id_collection_type .form-check-label {
|
||||||
|
display: inline-block;
|
||||||
|
padding: .375rem .75rem;
|
||||||
|
border: 1px solid #0d6efd;
|
||||||
|
border-radius: .375rem;
|
||||||
|
color: #0d6efd;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
#div_id_collection_type .form-check-input:focus + .form-check-label {
|
||||||
|
box-shadow: 0 0 0 .25rem rgba(13,110,253,.25);
|
||||||
|
}
|
||||||
|
#div_id_collection_type .form-check-input:checked + .form-check-label {
|
||||||
|
background-color: #0d6efd;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
/* small spacing tweak when legend present */
|
||||||
|
#div_id_collection_type fieldset { border: 0; padding: 0; margin: 0 0 1rem 0; }
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||||
|
|||||||
@@ -1,20 +1,43 @@
|
|||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated and collection %}
|
||||||
Collection: {{collection.name}}-> <a href="{% url 'atlas:collection_detail' pk=collection.pk %}">Overview</a> /
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mt-2 rounded">
|
||||||
<a href="{% url 'atlas:collection_case_update' collection.pk %}">Cases</a> /
|
<div class="container-fluid px-3">
|
||||||
<a href="{% url 'atlas:collection_history' collection.pk %}">History</a> /
|
<span class="navbar-text me-3 text-white">
|
||||||
<a href="{% url 'atlas:collection_mark_overview' collection.pk %}">Mark</a> /
|
<strong>Collection:</strong> {{ collection.name }}
|
||||||
<a href="{% url 'atlas:collection_scores_cid' collection.pk %}">Scores</a> /
|
</span>
|
||||||
<a href="{% url 'atlas:exam_cids' collection.pk %}">Candidates</a> /
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collectionNav" aria-controls="collectionNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<a href="{% url 'atlas:atlas_create_exam' pk=collection.pk %}">Add New Case</a> /
|
<span class="navbar-toggler-icon"></span>
|
||||||
<div class="floating-header">
|
</button>
|
||||||
<a href="{% url 'atlas:exam_update' collection.id %}" title="Edit the Collection">Edit</a>
|
|
||||||
\ <a href="{% url 'atlas:exam_deleted' collection.id %}" title="Delete the Collection">Delete</a>
|
|
||||||
\ <a href="{% url 'atlas:exam_clone' collection.id %}" title="Clone the Collection">Clone</a>
|
|
||||||
\ <a href="{% url 'atlas:collection_authors' collection.pk %}" title="Edit Authors">Authors</a>
|
|
||||||
|
|
||||||
{% if request.user.is_superuser %}
|
<div class="collapse navbar-collapse" id="collectionNav">
|
||||||
\ <a href="{% url 'admin:atlas_casecollection_change' collection.id %}" title="Edit the Collection using the admin interface">Admin Edit</a>
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
{% endif %}
|
<li class="nav-item"><a class="nav-link" href="{% url 'atlas:collection_detail' pk=collection.pk %}">Overview</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'atlas:collection_case_update' collection.pk %}">Cases</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'atlas:collection_history' collection.pk %}">History</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'atlas:collection_mark_overview' collection.pk %}">Mark</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'atlas:collection_scores_cid' collection.pk %}">Scores</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'atlas:exam_cids' collection.pk %}">Candidates</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'atlas:atlas_create_exam' pk=collection.pk %}">Add New Case</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" id="collectionActions" role="button" data-bs-toggle="dropdown" aria-expanded="false">Actions</a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark" aria-labelledby="collectionActions">
|
||||||
|
<li><a class="dropdown-item" href="{% url 'atlas:collection_case_update' collection.pk %}">Edit Cases</a></li>
|
||||||
|
<li><a class="dropdown-item" href="{% url 'atlas:exam_update' collection.id %}">Edit</a></li>
|
||||||
|
<li><a class="dropdown-item" href="{% url 'atlas:exam_clone' collection.id %}">Clone</a></li>
|
||||||
|
<li><a class="dropdown-item" href="{% url 'atlas:collection_authors' collection.pk %}">Authors</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item text-danger" href="{% url 'atlas:exam_deleted' collection.id %}">Delete</a></li>
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="{% url 'admin:atlas_casecollection_change' collection.id %}">Admin Edit</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,6 @@
|
|||||||
{% if collection %}
|
{% if collection %}
|
||||||
{% include "atlas/collection_headers.html" %}
|
{% include "atlas/collection_headers.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if exam %}
|
|
||||||
<a href="{% url 'atlas:exam_review_start' pk=exam.pk %}">Review</a> /
|
|
||||||
{% endif %}
|
|
||||||
{% comment %} Collection: {{collection.name}}-> <a href="{% url 'atlas:collection_detail' pk=exam.pk %}">Overview</a> /
|
{% comment %} Collection: {{collection.name}}-> <a href="{% url 'atlas:collection_detail' pk=exam.pk %}">Overview</a> /
|
||||||
<a href="{% url 'atlas:collection_mark_overview' exam.pk %}">Mark</a> /
|
<a href="{% url 'atlas:collection_mark_overview' exam.pk %}">Mark</a> /
|
||||||
<a href="{% url 'atlas:collection_scores_cid' exam.pk %}">Scores</a> /
|
<a href="{% url 'atlas:collection_scores_cid' exam.pk %}">Scores</a> /
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
<div class="btn-group" role="group" aria-label="{{ widget.name }}">
|
||||||
|
{% for val, label in widget.choices %}
|
||||||
|
{% with forloop.counter0 as idx %}
|
||||||
|
{% with id=widget.name|add:"_"|add:idx %}
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
class="btn-check"
|
||||||
|
name="{{ widget.name }}"
|
||||||
|
id="{{ widget.name }}_{{ idx }}"
|
||||||
|
value="{{ val }}"
|
||||||
|
{% if val|stringformat:"s" == widget.value|stringformat:"s" %}checked{% endif %}
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="btn btn-outline-primary {% if val|stringformat:"s" == widget.value|stringformat:"s" %}active{% endif %}"
|
||||||
|
for="{{ widget.name }}_{{ idx }}"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</label>
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
@@ -1385,6 +1385,10 @@ class CaseCollectionCreate(RevisionMixin, LoginRequiredMixin, CreateView):
|
|||||||
else:
|
else:
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
"""Redirect to the collection detail page after successful creation."""
|
||||||
|
return reverse("atlas:collection_detail", kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
|
class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
|
||||||
model = Series
|
model = Series
|
||||||
|
|||||||
Reference in New Issue
Block a user