From ddb5783f7fb802cda3140cff333f963a06412d8a Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 11 Aug 2025 09:57:14 +0100 Subject: [PATCH] Refactor CaseCollectionForm layout and add date fields with custom widgets for improved user experience --- atlas/forms.py | 112 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 96 insertions(+), 16 deletions(-) diff --git a/atlas/forms.py b/atlas/forms.py index 55e07acb..e9eb1af2 100755 --- a/atlas/forms.py +++ b/atlas/forms.py @@ -13,6 +13,7 @@ from django.forms import ( ValidationError, modelformset_factory, CheckboxSelectMultiple, + SplitDateTimeWidget, ) from django.forms import inlineformset_factory from django.shortcuts import get_object_or_404 @@ -68,7 +69,12 @@ from autocomplete import ( import logging -from generic.forms import ExamAuthorFormMixin, ExamGroupsFormMixin +from generic.forms import ( + ExamAuthorFormMixin, + ExamGroupsFormMixin, + SplitDateTimeFieldDefaultTime, + SplitDateTimeFieldDefaultTimeEnd, +) from crispy_forms.helper import FormHelper @@ -150,29 +156,103 @@ class CaseCollectionForm(ModelForm): if f in self.fields: user_fields.append(f) - other_fields = [f for f in self.fields if f not in show_fields and f not in user_fields] + # Explicitly define show fields for pre and post + show_pre_fields = [ + f + for f in [ + "show_title_pre", + "show_history_pre", + "show_description_pre", + "show_discussion_pre", + "show_report_pre", + ] + if f in self.fields + ] + show_post_fields = [ + f + for f in [ + "show_title_post", + "show_history_post", + "show_description_post", + "show_discussion_post", + "show_report_post", + ] + if f in self.fields + ] self.helper.layout = Layout( - Fieldset("Collection Details", *other_fields), - # Add grouped user fields if present + Fieldset( + "Collection Details", + "name", + Fieldset( + "Dates", + "restrict_to_dates", + Div( + Field( + "start_date", + wrapper_class="col-md-6", + css_class="form-group", + ), + Field( + "end_date", wrapper_class="col-md-6", css_class="form-group" + ), + css_class="form-row d-flex", + ), + ), + "active", + "publish_results", + "archive", + "open_access", + "candidates_only", + "authors_only", + "results_supervisor_visible", + "exam_open_access", + "markers", + "exam_mode", + "self_review", + "feedback_once_collection_complete", + "collection_type", + "viewer_mode", + ), Fieldset("Valid User Groups", *user_fields) if user_fields else None, Div( - Div( - Fieldset("Show fields (pre-exam)", *show_pre_fields), - css_class="col-md-6", - style="float:left;", - ), - Div( - Fieldset("Show fields (post-exam)", *show_post_fields), - css_class="col-md-6", - style="float:left;", - ), - css_class="row", - style="display: flex; flex-wrap: wrap;", + Div( + Fieldset("Show fields (pre-exam)", *show_pre_fields), + css_class="col-md-6", + style="float:left;", + ), + Div( + Fieldset("Show fields (post-exam)", *show_post_fields), + css_class="col-md-6", + style="float:left;", + ), + css_class="row", + style="display: flex; flex-wrap: wrap;", ), Submit("submit", "Save Collection", css_class="btn btn-primary"), ) + self.fields["start_date"] = SplitDateTimeFieldDefaultTime( + widget=SplitDateTimeWidget( + date_attrs={"type": "date", "class": "datepicker"}, + time_attrs={"type": "time", "class": "timepicker"}, + date_format="%Y-%m-%d", + time_format="%H:%M", + ), + required=False, + help_text="The date the exam is due to start (time is optional)", + ) + self.fields["end_date"] = SplitDateTimeFieldDefaultTimeEnd( + widget=SplitDateTimeWidget( + date_attrs={"type": "date", "class": "datepicker"}, + time_attrs={"type": "time", "class": "timepicker"}, + date_format="%Y-%m-%d", + time_format="%H:%M", + ), + required=False, + help_text="The date the exam is due to start (time is optional)", + ) + def save(self, commit=True): # Get the unsaved Case instance instance = ModelForm.save(self, False)