Skip to content
Snippets Groups Projects
Commit ac69f9c6 authored by Benjamin Hättasch's avatar Benjamin Hättasch
Browse files

Improve CV overview and reuse in scheduler

Move general ajax setup call to external js file
Move common functionality for CV loading to external js file
Visualize existing violations in scheduler
Add reloading function to scheduler
parent a1705215
No related branches found
No related tags found
1 merge request!137Improve scheduling
Pipeline #117797 passed
function loadCVs(url, callback_success, callback_error) {
$.ajax({
url: url,
type: 'GET',
success: callback_success,
error: callback_error
});
}
const default_cv_callback_error = function(response) {
alert("{% trans 'Cannot load current violations from server' %}");
}
...@@ -13,48 +13,14 @@ ...@@ -13,48 +13,14 @@
{% block extrahead %} {% block extrahead %}
{{ block.super }} {{ block.super }}
<script type="application/javascript" src="{% static "common/js/api.js" %}"></script>
<script type="application/javascript" src="{% static "AKScheduling/js/scheduling.js" %}"></script>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
// CSRF Protection/Authentication const url = "{% url "model:scheduling-constraint-violations-list" event_slug=event.slug %}";
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);
const callback_success = function(response) {
let table_html = ''; let table_html = '';
if(response.length > 0) { if(response.length > 0) {
...@@ -80,11 +46,12 @@ ...@@ -80,11 +46,12 @@
// Show violation list (potentially empty) in violations table // Show violation list (potentially empty) in violations table
$('#violationsTableBody').html(table_html); $('#violationsTableBody').html(table_html);
},
error: function (response) {
alert("{% trans 'Cannot load current violations from server' %}");
} }
});
// (Re-)Load constraint violations using AJAX and visualize using violation count badge and violation table
function reload() {
loadCVs(url, callback_success, default_cv_callback_error)
} }
reload(); reload();
......
...@@ -59,48 +59,17 @@ ...@@ -59,48 +59,17 @@
} }
</style> </style>
<script type="application/javascript" src="{% static "common/js/api.js" %}"></script>
<script type="application/javascript" src="{% static "AKScheduling/js/scheduling.js" %}"></script>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { 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);
}
}
});
// Place slots by dropping placeholders on calendar // Place slots by dropping placeholders on calendar
var containerEl = document.getElementById('unscheduled-slots'); var containerEl = document.getElementById('unscheduled-slots');
new FullCalendar.Draggable(containerEl, { new FullCalendar.Draggable(containerEl, {
itemSelector: '.unscheduled-slot', itemSelector: '.unscheduled-slot',
}); });
// Calendar // Calendar
var planEl = document.getElementById('planCalendar'); var planEl = document.getElementById('planCalendar');
...@@ -211,6 +180,58 @@ ...@@ -211,6 +180,58 @@
$('.unscheduled-slot').each(function() { $('.unscheduled-slot').each(function() {
$(this).tooltip({title: $(this).first().attr('data-details'), trigger: 'hover'}); $(this).tooltip({title: $(this).first().attr('data-details'), trigger: 'hover'});
}); });
const cv_url = "{% url "model:scheduling-constraint-violations-list" event_slug=event.slug %}";
const cv_callback_success = function(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++) {
if(response[i].manually_resolved)
table_html += '<tr class="text-muted"><td class="nowrap">{% fa5_icon "check" "fas" %} ';
else
table_html += '<tr><td>';
if(response[i].level_display==='{% trans "Violation" %}')
table_html += '{% fa5_icon "exclamation-circle" "fas" %}';
else
table_html += '{% fa5_icon "info-circle" "fas" %}';
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>"
}
}
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="2" class="text-center">{% trans "No violations" %}</td></tr>'
}
// Show violation list (potentially empty) in violations table
$('#violationsTableBody').html(table_html);
}
function reloadCVs() {
loadCVs(cv_url, cv_callback_success, default_cv_callback_error);
}
reloadCVs();
const reloadBtn = $('#reloadBtn');
function reload() {
plan.refetchEvents();
reloadCVs();
// TODO Reload unscheduled AKs
}
reloadBtn.click(reload);
}); });
</script> </script>
...@@ -218,16 +239,33 @@ ...@@ -218,16 +239,33 @@
<body> <body>
<div class="box p-3"> <div class="box p-3">
<div class="row header pb-2"> <div class="row header pb-2">
<div class="col-sm-10"> <div class="col">
<h2 class="d-inline">{% trans "Scheduling for" %} {{event}}</h2> <h5 class="d-inline ml-2"><a href="{% url 'admin:event_status' event.slug %}">{% trans "Event Status" %} {% fa5_icon "level-up-alt" "fas" %}</a></h5> <h2 class="d-inline">
<button class="btn btn-outline-warning" id="reloadBtn" style="vertical-align: text-bottom;">
<span id="reloadBtnVisDefault">{% fa5_icon "redo" "fas" %}</span>
</button>
{% trans "Scheduling for" %} {{event}}
</h2>
<h5 class="d-inline ml-2">
<a href="{% url 'admin:event_status' event.slug %}">{% trans "Event Status" %} {% fa5_icon "level-up-alt" "fas" %}</a>
</h5>
</div> </div>
<div class="col-sm-2"></div>
</div> </div>
<div class="row content"> <div class="row content">
<div class="col-md-10 col-lg-10"> <div class="col-md-8 col-lg-9 col-xl-10">
<div id="planCalendar"></div> <div id="planCalendar"></div>
</div> </div>
<div class="col-md-2 col-lg-2" id="unscheduled-slots"> <div class="col-md-4 col-lg-3 col-xl-2" id="sidebar">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#unscheduled-slots">{% trans "Unscheduled" %}</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#violations"><span id="violationCountBadge" class="badge badge-success">0</span> {% trans "Violation(s)" %}</a>
</li>
</ul>
<div id="sidebarContent" class="tab-content">
<div class="tab-pane fade show active" id="unscheduled-slots">
{% regroup slots_unscheduled by ak.track as slots_unscheduled_by_track_list %} {% regroup slots_unscheduled by ak.track as slots_unscheduled_by_track_list %}
{% for track_slots in slots_unscheduled_by_track_list %} {% for track_slots in slots_unscheduled_by_track_list %}
{% if track_slots.grouper %} {% if track_slots.grouper %}
...@@ -241,6 +279,26 @@ ...@@ -241,6 +279,26 @@
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
</div> </div>
<div class="tab-pane fade" id="violations">
<table class="table table-striped mt-4 mb-4">
<thead>
<tr>
<th>{% trans "Level" %}</th>
<th>{% trans "Problem" %}</th>
</tr>
</thead>
<tbody id="violationsTableBody">
<tr class="text-muted">
<td colspan="2" class="text-center">
{% trans "No violations" %}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div> </div>
<div class="row footer"> <div class="row footer">
<!-- Currently not used --> <!-- Currently not used -->
......
// 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);
}
}
});
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment