Skip to content
Snippets Groups Projects
Commit 9d94ec2e authored by Benjamin Hättasch's avatar Benjamin Hättasch Committed by Nadja Geisler
Browse files

Introduce basic constraint violation admin view showing current violations (using async reloading)

parent ec0d2a62
No related branches found
No related tags found
1 merge request!99Constraint Violation checking & visualization
Pipeline #22504 passed
......@@ -74,6 +74,10 @@
<a class="btn btn-success"
href="{% url 'admin:schedule' event_slug=event.slug %}">{% trans "Scheduling" %}</a>
{% if "AKScheduling | is_installed" %}
<a class="btn btn-success"
href="{% url 'admin:constraint-violations' slug=event.slug %}">{% trans "Constraint Violations" %} <span class="badge badge-secondary">{{ event.constraintviolation_set.count }}</span></a>
{% endif %}
<a class="btn btn-success"
href="{% url 'admin:tracks_manage' event_slug=event.slug %}">{% trans "Manage ak tracks" %}</a>
<a class="btn btn-success"
......
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-04-29 22:48+0000\n"
"POT-Creation-Date: 2021-05-09 18:23+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -17,49 +17,92 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:11
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:11
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:10
msgid "Scheduling for"
msgstr "Scheduling für"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:126
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:74
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:128
msgid "No violations"
msgstr "Keine Verletzungen"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:81
msgid "Cannot load current violations from server"
msgstr "Kann die aktuellen Verletzungen nicht vom Server laden"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:106
msgid "Violation(s)"
msgstr "Verletzung(en)"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:109
msgid "Auto reload?"
msgstr "Automatisch neu laden?"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:113
msgid "Reload now"
msgstr "Jetzt neu laden"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:118
msgid "Violation"
msgstr "Verletzung"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:119
msgid "Problem"
msgstr "Problem"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:120
msgid "Details"
msgstr "Details"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:121
msgid "Since"
msgstr "Seit"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:134
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:243
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:197
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:34
msgid "Event Status"
msgstr "Event-Status"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:136
msgid "Scheduling"
msgstr "Scheduling"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:129
msgid "Name of new ak track"
msgstr "Name des neuen AK-Tracks"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:142
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:145
msgid "Could not create ak track"
msgstr "Konnte neuen AK-Track nicht anlegen"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:168
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:171
msgid "Could not update ak track name"
msgstr "Konnte Namen des AK-Tracks nicht ändern"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:174
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:177
msgid "Do you really want to delete this ak track?"
msgstr "Soll dieser AK-Track wirklich gelöscht werden?"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:188
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:191
msgid "Could not delete ak track"
msgstr "AK-Track konnte nicht gelöscht werden"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:200
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:203
msgid "Manage AK Tracks"
msgstr "AK-Tracks verwalten"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:201
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:204
msgid "Add ak track"
msgstr "AK-Track hinzufügen"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:206
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:209
msgid "AKs without track"
msgstr "AKs ohne Track"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:240
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:197
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:34
msgid "Event Status"
msgstr "Event-Status"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:87
msgid "Day (Horizontal)"
msgstr "Tag (horizontal)"
......
{% extends "admin/base_site.html" %}
{% load tags_AKModel %}
{% load i18n %}
{% load l10n %}
{% load tz %}
{% load static %}
{% load tags_AKPlan %}
{% load fontawesome_5 %}
{% block title %}{% trans "Scheduling for" %} {{event}}{% endblock %}
{% block extrahead %}
{{ block.super }}
<script>
document.addEventListener('DOMContentLoaded', function () {
// CSRF Protection/Authentication
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// (Re-)Load constraint violations using AJAX and visualize using violation count badge and violation table
function reload() {
$.ajax({
url: "{% url "model:scheduling-constraint-violations-list" event_slug=event.slug %}",
type: 'GET',
success: function (response) {
console.log(response);
let table_html = '';
if(response.length > 0) {
// Update violation count badge
$('#violationCountBadge').html(response.length).removeClass('badge-success').addClass('badge-warning');
// Update violations table
for(let i=0;i<response.length;i++) {
table_html += "<tr><td>" + response[i].level_display + "</td><td>" + response[i].type_display + "</td><td>" + response[i].details + "</td><td>" + response[i].timestamp_display + "</td><td></td></tr>";
}
}
else {
// Update violation count badge
$('#violationCountBadge').html(0).removeClass('badge-warning').addClass('badge-success');
// Update violations table
table_html ='<tr class="text-muted"><td colspan="5" class="text-center">{% trans "No violations" %}</td></tr>'
}
// Show violation list (potentially empty) in violations table
$('#violationsTableBody').html(table_html);
},
error: function (response) {
alert("{% trans 'Cannot load current violations from server' %}");
}
});
}
reload();
// Bind reload button
$('#btnReloadNow').click(reload);
// Toggle automatic reloading (every 30 s) based on checkbox
let autoReloadInterval = undefined;
$('#cbxAutoReload').change(function () {
if(this.checked) {
autoReloadInterval = setInterval(reload, 30*1000);
}
else {
if(autoReloadInterval !== undefined)
clearInterval(autoReloadInterval);
}
});
});
</script>
{% endblock extrahead %}
{% block content %}
<h4 class="mt-4 mb-4"><span id="violationCountBadge" class="badge badge-success">0</span> {% trans "Violation(s)" %}</h4>
<input type="checkbox" id="cbxAutoReload">
<label for="cbxAutoReload">{% trans "Auto reload?" %}</label>
<br>
<a href="#" id="btnReloadNow" class="btn btn-info">{% fa5_icon "sync-alt" "fas" %} {% trans "Reload now" %}</a>
<table class="table table-striped mt-4 mb-4">
<thead>
<tr>
<th>{% trans "Violation" %}</th>
<th>{% trans "Problem" %}</th>
<th>{% trans "Details" %}</th>
<th>{% trans "Since" %}</th>
<th></th>
</tr>
</thead>
<tbody id="violationsTableBody">
<tr class="text-muted">
<td colspan="5" class="text-center">
{% trans "No violations" %}
</td>
</tr>
</tbody>
</table>
<a href="{% url 'admin:event_status' event.slug %}">{% trans "Event Status" %}</a>
&middot;
<a href="{% url 'admin:schedule' event.slug %}">{% trans "Scheduling" %}</a>
{% endblock %}
from django.urls import path
from AKScheduling.views import SchedulingAdminView, UnscheduledSlotsAdminView, TrackAdminView
from AKScheduling.views import SchedulingAdminView, UnscheduledSlotsAdminView, TrackAdminView, \
ConstraintViolationsAdminView
def get_admin_urls_scheduling(admin_site):
......@@ -9,6 +10,8 @@ def get_admin_urls_scheduling(admin_site):
name="schedule"),
path('<slug:event_slug>/unscheduled/', admin_site.admin_view(UnscheduledSlotsAdminView.as_view()),
name="slots_unscheduled"),
path('<slug:slug>/constraint-violations/', admin_site.admin_view(ConstraintViolationsAdminView.as_view()),
name="constraint-violations"),
path('<slug:event_slug>/tracks/', admin_site.admin_view(TrackAdminView.as_view()),
name="tracks_manage"),
]
from django.views.generic import ListView
from django.views.generic import ListView, DetailView
from django.utils.translation import gettext_lazy as _
from AKModel.models import AKSlot, AKTrack
from AKModel.models import AKSlot, AKTrack, Event
from AKModel.views import AdminViewMixin, FilterByEventSlugMixin
......@@ -47,3 +47,14 @@ class TrackAdminView(AdminViewMixin, FilterByEventSlugMixin, ListView):
context = super().get_context_data(object_list=object_list, **kwargs)
context["aks_without_track"] = self.event.ak_set.filter(track=None)
return context
class ConstraintViolationsAdminView(AdminViewMixin, DetailView):
template_name = "admin/AKScheduling/constraint_violations.html"
model = Event
context_object_name = "event"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = f"{_('Constraint violations for')} {context['event']}"
return context
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment