From 53acfb9b7857a7cb6867b47a1abfe530f76e2aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?= <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de> Date: Sat, 20 Apr 2024 18:28:07 +0200 Subject: [PATCH 1/4] Hide headings for empty constraints in detail representation of AKSlot This will remove empty lines from the "bubbles" containing details in scheduler. This implements #215 --- AKModel/models.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/AKModel/models.py b/AKModel/models.py index 926b7e0e..fc8ab147 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -367,7 +367,7 @@ class AK(models.Model): @property def details(self): """ - Generate a detailled string representation, e.g., for usage in scheduling + Generate a detailed string representation, e.g., for usage in scheduling :return: string representation of that AK with all details :rtype: str """ @@ -376,15 +376,19 @@ class AK(models.Model): from AKModel.availability.models import Availability availabilities = ', \n'.join(f'{a.simplified}' for a in Availability.objects.select_related('event') .filter(ak=self)) - return f"""{self.name}{" (R)" if self.reso else ""}: + detail_string = f"""{self.name}{" (R)" if self.reso else ""}: {self.owners_list} - {_('Interest')}: {self.interest} - {_("Requirements")}: {", ".join(str(r) for r in self.requirements.all())} - {_("Conflicts")}: {", ".join(str(c) for c in self.conflicts.all())} - {_("Prerequisites")}: {", ".join(str(p) for p in self.prerequisites.all())} - {_("Availabilities")}: \n{availabilities}""" + {_('Interest')}: {self.interest}""" + if self.requirements.count() > 0: + detail_string += f"\n{_('Requirements')}: {', '.join(str(r) for r in self.requirements.all())}" + if self.conflicts.count() > 0: + detail_string += f"\n{_('Conflicts')}: {', '.join(str(c) for c in self.conflicts.all())}" + if self.prerequisites.count() > 0: + detail_string += f"\n{_('Prerequisites')}: {', '.join(str(p) for p in self.prerequisites.all())}" + detail_string += f"\n{_('Availabilities')}: \n{availabilities}" + return detail_string @property def owners_list(self): -- GitLab From 15914cf9dc6032fd72b2ecf3b54f67be24d22541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?= <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de> Date: Sat, 20 Apr 2024 18:55:58 +0200 Subject: [PATCH 2/4] Count only non-resolved CVs in scheduler and CV overview This implements #201 --- .../AKScheduling/constraint_violations.html | 19 +++++++++++------- .../admin/AKScheduling/scheduling.html | 20 +++++++++++-------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/AKScheduling/templates/admin/AKScheduling/constraint_violations.html b/AKScheduling/templates/admin/AKScheduling/constraint_violations.html index 6a71f9b4..e8454247 100644 --- a/AKScheduling/templates/admin/AKScheduling/constraint_violations.html +++ b/AKScheduling/templates/admin/AKScheduling/constraint_violations.html @@ -23,26 +23,31 @@ const callback_success = function(response) { let table_html = ''; + let unresolved_constraint_violations = 0; + if(response.length > 0) { - // Update violation count badge - $('#violationCountBadge').html(response.length).removeClass('bg-success').addClass('bg-warning'); // Update violations table for(let i=0;i<response.length;i++) { - if(response[i].manually_resolved) + if(response[i].manually_resolved) { table_html += '<tr class="text-muted"><td class="nowrap">{% fa6_icon "check" "fas" %}</td>'; - else + } + else { table_html += '<tr><td></td>'; + unresolved_constraint_violations++; + } table_html += "<td>" + response[i].level_display + "</td><td>" + response[i].type_display + "</td><td>" + response[i].details + "</td><td class='nowrap'>" + response[i].timestamp_display + "</td><td><a href='" + response[i].edit_url + "'><i class='btn btn-primary fa fa-pen'></i></a></td></tr>"; } } else { - // Update violation count badge - $('#violationCountBadge').html(0).removeClass('bg-warning').addClass('bg-success'); - // Update violations table table_html ='<tr class="text-muted"><td colspan="5" class="text-center">{% trans "No violations" %}</td></tr>' } + // Update violation count badge + if(unresolved_constraint_violations > 0) + $('#violationCountBadge').html(unresolved_constraint_violations).removeClass('bg-success').addClass('bg-warning'); + else + $('#violationCountBadge').html(0).removeClass('bg-warning').addClass('bg-success'); // Show violation list (potentially empty) in violations table $('#violationsTableBody').html(table_html); diff --git a/AKScheduling/templates/admin/AKScheduling/scheduling.html b/AKScheduling/templates/admin/AKScheduling/scheduling.html index 1be3071c..8d592aec 100644 --- a/AKScheduling/templates/admin/AKScheduling/scheduling.html +++ b/AKScheduling/templates/admin/AKScheduling/scheduling.html @@ -215,20 +215,24 @@ if(response.length > 0) { // Update violations table for(let i=0;i<response.length;i++) { - if(response[i].manually_resolved) - table_html += '<tr class="text-muted"><td class="nowrap">{% fa6_icon "check" "fas" %} '; + let icon_html = ''; + let muted_html = ''; + if(response[i].manually_resolved) { + icon_html = '{% fa6_icon "check" "fas" %} '; + muted_html = 'text-muted'; + } else { - table_html += '<tr><td>'; unresolved_violations_count++; } if(response[i].level_display==='{% trans "Violation" %}') - table_html += '{% fa6_icon "exclamation-triangle" "fas" %}'; + icon_html += '{% fa6_icon "exclamation-triangle" "fas" %}'; else - table_html += '{% fa6_icon "info-circle" "fas" %}'; + icon_html += '{% fa6_icon "info-circle" "fas" %}'; + table_html += '<tr class="'+ muted_html+ '"><td class="nowrap">' + icon_html; table_html += "</td><td class='small'>" + response[i].type_display + "</td></tr>"; - table_html += "<tr><td colspan='2' class='small'>" + response[i].details + "</td></tr>" + table_html += "<tr class='" + muted_html + "'><td colspan='2' class='small'>" + response[i].details + "</td></tr>" } } else { @@ -238,7 +242,7 @@ // Update violation count badge if(unresolved_violations_count > 0) - $('#violationCountBadge').html(response.length).removeClass('bg-success').addClass('bg-warning'); + $('#violationCountBadge').html(unresolved_violations_count).removeClass('bg-success').addClass('bg-warning'); else $('#violationCountBadge').html(0).removeClass('bg-warning').addClass('bg-success'); @@ -358,7 +362,7 @@ {% endfor %} </div> <div class="tab-pane fade" id="violations"> - <table class="table table-striped mt-4 mb-4"> + <table class="table mt-4 mb-4"> <thead> <tr> <th>{% trans "Level" %}</th> -- GitLab From 0f312eb8823f507512ffed0408b4a4e0706c8eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?= <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de> Date: Sat, 20 Apr 2024 19:01:28 +0200 Subject: [PATCH 3/4] Only check room size if interest > -1 This prevents warning for AKs where interest was not specified and room capacity is quite small. This resolves #209 --- AKScheduling/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AKScheduling/models.py b/AKScheduling/models.py index 769527f7..1495f311 100644 --- a/AKScheduling/models.py +++ b/AKScheduling/models.py @@ -80,8 +80,8 @@ def check_capacity_for_slot(slot: AKSlot): :rtype: ConstraintViolation or None """ - # If slot is scheduled in a room - if slot.room and slot.room.capacity >= 0: + # If slot is scheduled in a room and interest was specified + if slot.room and slot.room.capacity >= 0 and slot.ak.interest >= 0: # Create a violation if interest exceeds room capacity if slot.room.capacity < slot.ak.interest: c = ConstraintViolation( -- GitLab From d5fad1a61b8e26b0f1a166c62dd97f0819fc6be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?= <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de> Date: Sat, 20 Apr 2024 19:54:37 +0200 Subject: [PATCH 4/4] Fix small code style issues --- AKModel/forms.py | 3 +++ AKPlan/views.py | 1 + 2 files changed, 4 insertions(+) diff --git a/AKModel/forms.py b/AKModel/forms.py index 24074ecd..4d1fe7ef 100644 --- a/AKModel/forms.py +++ b/AKModel/forms.py @@ -14,6 +14,9 @@ from AKModel.models import Event, AKCategory, AKRequirement, Room class DateTimeInput(forms.DateInput): + """ + Simple widget for datetime input fields using the HTML5 datetime-local input type + """ input_type = 'datetime-local' diff --git a/AKPlan/views.py b/AKPlan/views.py index fdd4e7e8..4123256e 100644 --- a/AKPlan/views.py +++ b/AKPlan/views.py @@ -83,6 +83,7 @@ class PlanScreenView(PlanIndexView): return redirect(reverse_lazy("plan:plan_overview", kwargs={"event_slug": self.event.slug})) return s + # pylint: disable=attribute-defined-outside-init def get_queryset(self): now = datetime.now().astimezone(self.event.timezone) # Wall during event: Adjust, show only parts in the future -- GitLab