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

Introduce manage view for ak tracks

This view can be used to sort aks into tracks using drag and drop. You can also create new ak tracks or delete them.

Add js dependency for drag and drop of lists.
Activate add, update, delete methids to AKTrack API and update method to AK API.
Add and link (on status page) new admin view for management.
Add tags list property to AK model.
Introduce translations for AKScheduling app.
Update translations.
parent 4fa3f6f0
No related branches found
No related tags found
No related merge requests found
......@@ -94,6 +94,18 @@ class AKTrackAdmin(admin.ModelAdmin):
kwargs['initial'] = Event.get_next_active()
return super(AKTrackAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
def get_urls(self):
urls = super().get_urls()
custom_urls = []
if apps.is_installed("AKScheduling"):
from AKScheduling.views import TrackAdminView
custom_urls.extend([
path('<slug:event_slug>/manage/', self.admin_site.admin_view(TrackAdminView.as_view()),
name="tracks_manage"),
])
return custom_urls + urls
@admin.register(AKTag)
class AKTagAdmin(admin.ModelAdmin):
......
......@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-11-03 20:41+0000\n"
"POT-Creation-Date: 2021-02-17 23:56+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"
......@@ -11,28 +11,32 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: AKModel/admin.py:41 AKModel/admin.py:42
#: AKModel/admin.py:43 AKModel/admin.py:44
#: AKModel/templates/admin/AKModel/status.html:7
#: AKModel/templates/admin/ak_index.html:15
msgid "Status"
msgstr "Status"
#: AKModel/admin.py:120
#: AKModel/admin.py:134
msgid "Wish"
msgstr "AK-Wunsch"
#: AKModel/admin.py:126
#: AKModel/admin.py:140
msgid "Is wish"
msgstr "Ist ein Wunsch"
#: AKModel/admin.py:127
#: AKModel/admin.py:141
msgid "Is not a wish"
msgstr "Ist kein Wunsch"
#: AKModel/admin.py:154
#: AKModel/admin.py:168
msgid "Export to wiki syntax"
msgstr "In Wiki-Syntax exportieren"
#: AKModel/admin.py:264
msgid "AK Details"
msgstr "AK-Details"
#: AKModel/availability/forms.py:20 AKModel/availability/models.py:239
msgid "Availability"
msgstr "Verfügbarkeit"
......@@ -59,14 +63,14 @@ msgstr "Bitte Verfügbarkeiten eintragen!"
#: AKModel/availability/models.py:38 AKModel/models.py:47 AKModel/models.py:76
#: AKModel/models.py:128 AKModel/models.py:147 AKModel/models.py:179
#: AKModel/models.py:233 AKModel/models.py:292 AKModel/models.py:324
#: AKModel/models.py:410
#: AKModel/models.py:233 AKModel/models.py:296 AKModel/models.py:328
#: AKModel/models.py:435
msgid "Event"
msgstr "Event"
#: AKModel/availability/models.py:39 AKModel/models.py:77 AKModel/models.py:129
#: AKModel/models.py:148 AKModel/models.py:180 AKModel/models.py:234
#: AKModel/models.py:293 AKModel/models.py:325 AKModel/models.py:411
#: AKModel/models.py:297 AKModel/models.py:329 AKModel/models.py:436
msgid "Associated event"
msgstr "Zugehöriges Event"
......@@ -78,8 +82,8 @@ msgstr "Person"
msgid "Person whose availability this is"
msgstr "Person deren Verfügbarkeit hier abgebildet wird"
#: AKModel/availability/models.py:56 AKModel/models.py:296
#: AKModel/models.py:315 AKModel/models.py:419
#: AKModel/availability/models.py:56 AKModel/models.py:300
#: AKModel/models.py:319 AKModel/models.py:444
msgid "Room"
msgstr "Raum"
......@@ -88,7 +92,7 @@ msgid "Room whose availability this is"
msgstr "Raum dessen Verfügbarkeit hier abgebildet wird"
#: AKModel/availability/models.py:65 AKModel/models.py:239
#: AKModel/models.py:314 AKModel/models.py:366
#: AKModel/models.py:318 AKModel/models.py:391
msgid "AK"
msgstr "AK"
......@@ -97,7 +101,7 @@ msgid "AK whose availability this is"
msgstr "Verfügbarkeiten"
#: AKModel/availability/models.py:74 AKModel/models.py:132
#: AKModel/models.py:425
#: AKModel/models.py:450
msgid "AK Category"
msgstr "AK-Kategorie"
......@@ -111,7 +115,7 @@ msgstr "Verfügbarkeiten"
#: AKModel/models.py:16 AKModel/models.py:123 AKModel/models.py:144
#: AKModel/models.py:163 AKModel/models.py:177 AKModel/models.py:195
#: AKModel/models.py:285
#: AKModel/models.py:289
msgid "Name"
msgstr "Name"
......@@ -261,7 +265,7 @@ msgstr "Internet Link"
msgid "Link to Homepage"
msgstr "Link zu Homepage oder Webseite"
#: AKModel/models.py:80 AKModel/models.py:418
#: AKModel/models.py:80 AKModel/models.py:443
msgid "AK Owner"
msgstr "AK-Leitung"
......@@ -321,7 +325,7 @@ msgstr "AK-Tags"
msgid "Name of the Requirement"
msgstr "Name der Anforderung"
#: AKModel/models.py:183 AKModel/models.py:422
#: AKModel/models.py:183 AKModel/models.py:447
msgid "AK Requirement"
msgstr "AK-Anforderung"
......@@ -405,7 +409,7 @@ msgstr "AK präsentieren"
msgid "Present results of this AK"
msgstr "Die Ergebnisse dieses AKs vorstellen"
#: AKModel/models.py:218 AKModel/templates/admin/AKModel/status.html:83
#: AKModel/models.py:218 AKModel/templates/admin/AKModel/status.html:85
msgid "Requirements"
msgstr "Anforderungen"
......@@ -458,241 +462,246 @@ msgstr "Interessenszähler"
msgid "People who have indicated interest online"
msgstr "Anzahl Personen, die online Interesse bekundet haben"
#: AKModel/models.py:240 AKModel/models.py:413
#: AKModel/models.py:240 AKModel/models.py:438
#: AKModel/templates/admin/AKModel/status.html:49
#: AKModel/templates/admin/AKModel/status.html:56
msgid "AKs"
msgstr "AKs"
#: AKModel/models.py:285
#: AKModel/models.py:289
msgid "Name or number of the room"
msgstr "Name oder Nummer des Raums"
#: AKModel/models.py:286
#: AKModel/models.py:290
msgid "Location"
msgstr "Ort"
#: AKModel/models.py:287
#: AKModel/models.py:291
msgid "Name or number of the location"
msgstr "Name oder Nummer des Ortes"
#: AKModel/models.py:288
#: AKModel/models.py:292
msgid "Capacity"
msgstr "Kapazität"
#: AKModel/models.py:288
#: AKModel/models.py:292
msgid "Maximum number of people"
msgstr "Maximale Personenzahl"
#: AKModel/models.py:289
#: AKModel/models.py:293
msgid "Properties"
msgstr "Eigenschaften"
#: AKModel/models.py:290
#: AKModel/models.py:294
msgid "AK requirements fulfilled by the room"
msgstr "AK-Anforderungen, die dieser Raum erfüllt"
#: AKModel/models.py:297 AKModel/templates/admin/AKModel/status.html:33
#: AKModel/models.py:301 AKModel/templates/admin/AKModel/status.html:33
msgid "Rooms"
msgstr "Räume"
#: AKModel/models.py:314
#: AKModel/models.py:318
msgid "AK being mapped"
msgstr "AK, der zugeordnet wird"
#: AKModel/models.py:316
#: AKModel/models.py:320
msgid "Room the AK will take place in"
msgstr "Raum in dem der AK stattfindet"
#: AKModel/models.py:317
#: AKModel/models.py:321
msgid "Slot Begin"
msgstr "Beginn des Slots"
#: AKModel/models.py:317
#: AKModel/models.py:321
msgid "Time and date the slot begins"
msgstr "Zeit und Datum zu der der AK beginnt"
#: AKModel/models.py:319
#: AKModel/models.py:323
msgid "Duration"
msgstr "Dauer"
#: AKModel/models.py:320
#: AKModel/models.py:324
msgid "Length in hours"
msgstr "Länge in Stunden"
#: AKModel/models.py:322
#: AKModel/models.py:326
msgid "Scheduling fixed"
msgstr "Planung fix"
#: AKModel/models.py:322
#: AKModel/models.py:326
msgid "Length and time of this AK should not be changed"
msgstr "Dauer und Zeit dieses AKs sollten nicht verändert werden"
#: AKModel/models.py:327
#: AKModel/models.py:331
msgid "Last update"
msgstr "Letzte Aktualisierung"
#: AKModel/models.py:330
#: AKModel/models.py:334
msgid "AK Slot"
msgstr "AK-Slot"
#: AKModel/models.py:331 AKModel/models.py:415
#: AKModel/models.py:335 AKModel/models.py:440
msgid "AK Slots"
msgstr "AK-Slot"
#: AKModel/models.py:345
#: AKModel/models.py:357 AKModel/models.py:366
msgid "Not scheduled yet"
msgstr "Noch nicht geplant"
#: AKModel/models.py:367
#: AKModel/models.py:392
#, fuzzy
#| msgid "Track the AK belongs to"
msgid "AK this message belongs to"
msgstr "Track zu dem der AK gehört"
#: AKModel/models.py:368
#: AKModel/models.py:393
msgid "Message text"
msgstr "Nachrichtentext"
#: AKModel/models.py:369
#: AKModel/models.py:394
msgid "Message to the organizers. This is not publicly visible."
msgstr ""
"Nachricht an die Organisator*innen. Diese ist nicht öffentlich sichtbar."
#: AKModel/models.py:373
#: AKModel/models.py:398
msgid "AK Orga Message"
msgstr "AK-Organachricht"
#: AKModel/models.py:374
#: AKModel/models.py:399
msgid "AK Orga Messages"
msgstr "AK-Organachrichten"
#: AKModel/models.py:383
#: AKModel/models.py:408
msgid "Constraint Violation"
msgstr "Constraintverletzung"
#: AKModel/models.py:384
#: AKModel/models.py:409
msgid "Constraint Violations"
msgstr "Constraintverletzungen"
#: AKModel/models.py:388
#: AKModel/models.py:413
msgid "Owner has two parallel slots"
msgstr "Leitung hat zwei Slots parallel"
#: AKModel/models.py:389
#: AKModel/models.py:414
msgid "AK Slot was scheduled outside the AK's availabilities"
msgstr "AK Slot wurde außerhalb der Verfügbarkeit des AKs platziert"
#: AKModel/models.py:390
#: AKModel/models.py:415
msgid "Room has two AK slots scheduled at the same time"
msgstr "Raum hat AK Slots gleichzeitig"
#: AKModel/models.py:391
#: AKModel/models.py:416
msgid "Room does not satisfy the requirement of the scheduled AK"
msgstr "Room erfüllt die Anforderungen des platzierten AKs nicht"
#: AKModel/models.py:392
#: AKModel/models.py:417
msgid "AK Slot is scheduled at the same time as an AK listed as a conflict"
msgstr "AK Slot wurde wurde zur gleichen Zeit wie ein Konflikt des AKs platziert"
msgstr ""
"AK Slot wurde wurde zur gleichen Zeit wie ein Konflikt des AKs platziert"
#: AKModel/models.py:393
#: AKModel/models.py:418
msgid "AK Slot is scheduled before an AK listed as a prerequisite"
msgstr "AK Slot wurde vor einem als Voraussetzung gelisteten AK platziert"
#: AKModel/models.py:395
msgid "AK Slot for AK with intention to submit a resolution is scheduled after "
#: AKModel/models.py:420
msgid ""
"AK Slot for AK with intention to submit a resolution is scheduled after "
"resolution deadline"
msgstr "AK Slot eines AKs mit Resoabsicht wurde nach der Resodeadline platziert"
msgstr ""
"AK Slot eines AKs mit Resoabsicht wurde nach der Resodeadline platziert"
#: AKModel/models.py:396
#: AKModel/models.py:421
msgid "AK Slot in a category is outside that categories availabilities"
msgstr "AK Slot wurde außerhalb der Verfügbarkeiten seiner Kategorie"
#: AKModel/models.py:397
#: AKModel/models.py:422
msgid "Two AK Slots for the same AK scheduled at the same time"
msgstr "Zwei AK Slots eines AKs wurden zur selben Zeit platziert"
#: AKModel/models.py:398
#: AKModel/models.py:423
msgid "AK Slot is scheduled in a room with less space than interest"
msgstr "AK Slot wurde in einem Raum mit weniger Plätzen als am AK Interessierten platziert"
msgstr ""
"AK Slot wurde in einem Raum mit weniger Plätzen als am AK Interessierten "
"platziert"
#: AKModel/models.py:399
#: AKModel/models.py:424
msgid "AK Slot is scheduled outside the event's availabilities"
msgstr "AK Slot wurde außerhalb der Verfügbarkeit des Events platziert"
#: AKModel/models.py:402
#: AKModel/models.py:427
msgid "Warning"
msgstr "Warnung"
#: AKModel/models.py:403
#: AKModel/models.py:428
msgid "Violation"
msgstr "Verletzung"
#: AKModel/models.py:405
#: AKModel/models.py:430
msgid "Type"
msgstr "Art"
#: AKModel/models.py:406
#: AKModel/models.py:431
msgid "Type of violation, i.e. what kind of constraint was violated"
msgstr "Art der Verletzung, gibt an welche Art Constraint verletzt wurde"
#: AKModel/models.py:407
#: AKModel/models.py:432
msgid "Level"
msgstr "Level"
#: AKModel/models.py:408
#: AKModel/models.py:433
msgid "Severity level of the violation"
msgstr "Schweregrad der Verletzung"
#: AKModel/models.py:414
#: AKModel/models.py:439
msgid "AK(s) belonging to this constraint"
msgstr "AK(s), die zu diesem Constraint gehören"
#: AKModel/models.py:416
#: AKModel/models.py:441
msgid "AK Slot(s) belonging to this constraint"
msgstr "AK Slot(s), die zu diesem Constraint gehören"
#: AKModel/models.py:418
#: AKModel/models.py:443
msgid "AK Owner belonging to this constraint"
msgstr "AK Leitung(en), die zu diesem Constraint gehören"
#: AKModel/models.py:420
#: AKModel/models.py:445
msgid "Room belonging to this constraint"
msgstr "Raum, der zu diesem Constraint gehört"
#: AKModel/models.py:423
#: AKModel/models.py:448
msgid "AK Requirement belonging to this constraint"
msgstr "AK Anforderung, die zu diesem Constraint gehört"
#: AKModel/models.py:425
#: AKModel/models.py:450
msgid "AK Category belonging to this constraint"
msgstr "AK Kategorie, di zu diesem Constraint gehört"
#: AKModel/models.py:427
#: AKModel/models.py:452
msgid "Comment"
msgstr "Kommentar"
#: AKModel/models.py:427
#: AKModel/models.py:452
msgid "Comment or further details for this violation"
msgstr "Kommentar oder weitere Details zu dieser Vereletzung"
#: AKModel/models.py:430
#: AKModel/models.py:455
msgid "Timestamp"
msgstr "Timestamp"
#: AKModel/models.py:430
#: AKModel/models.py:455
msgid "Time of creation"
msgstr "Zeitpunkt der ERstellung"
#: AKModel/models.py:431
#: AKModel/models.py:456
msgid "Manually Resolved"
msgstr "Manuell behoben"
#: AKModel/models.py:432
#: AKModel/models.py:457
msgid "Mark this violation manually as resolved"
msgstr "Markiere diese Verletzung manuell als behoben"
#: AKModel/models.py:454
#: AKModel/models.py:479
msgid "Details"
msgstr "Details"
......@@ -783,26 +792,30 @@ msgid "Scheduling"
msgstr "Scheduling"
#: AKModel/templates/admin/AKModel/status.html:78
msgid "Manage ak tracks"
msgstr "AK-Tracks verwalten"
#: AKModel/templates/admin/AKModel/status.html:80
msgid "Export AKs as CSV"
msgstr "AKs als CSV exportieren"
#: AKModel/templates/admin/AKModel/status.html:80
#: AKModel/templates/admin/AKModel/status.html:82
msgid "Export AKs for Wiki"
msgstr "AKs im Wiki-Format exportieren"
#: AKModel/templates/admin/AKModel/status.html:85
#: AKModel/templates/admin/AKModel/status.html:87
msgid "No requirements yet"
msgstr "Bisher keine Anforderungen"
#: AKModel/templates/admin/AKModel/status.html:98
#: AKModel/templates/admin/AKModel/status.html:100
msgid "Add Requirement"
msgstr "Anforderungen hinzufügen"
#: AKModel/templates/admin/AKModel/status.html:101
#: AKModel/templates/admin/AKModel/status.html:103
msgid "Messages"
msgstr "Nachrichten"
#: AKModel/templates/admin/AKModel/status.html:103
#: AKModel/templates/admin/AKModel/status.html:105
msgid "Delete all messages"
msgstr "Alle Nachrichten löschen"
......@@ -810,19 +823,19 @@ msgstr "Alle Nachrichten löschen"
msgid "Active Events"
msgstr "Aktive Events"
#: AKModel/views.py:130
#: AKModel/views.py:135
msgid "Event Status"
msgstr "Eventstatus"
#: AKModel/views.py:144
#: AKModel/views.py:149
msgid "AK CSV Export"
msgstr "AK-CSV-Export"
#: AKModel/views.py:158
#: AKModel/views.py:163
msgid "AK Wiki Export"
msgstr "AK-Wiki-Export"
#: AKModel/views.py:178
#: AKModel/views.py:183
msgid "AK Orga Messages successfully deleted"
msgstr "AK-Organachrichten erfolgreich gelöscht"
......
......@@ -266,6 +266,10 @@ class AK(models.Model):
def durations_list(self):
return ", ".join(str(slot.duration) for slot in self.akslot_set.all())
@property
def tags_list(self):
return ", ".join(str(tag) for tag in self.tags.all())
@property
def wish(self):
return self.owners.count() == 0
......
......@@ -74,6 +74,8 @@
<a class="btn btn-success"
href="{% url 'admin:schedule' event_slug=event.slug %}">{% trans "Scheduling" %}</a>
<a class="btn btn-success"
href="{% url 'admin:tracks_manage' event_slug=event.slug %}">{% trans "Manage ak tracks" %}</a>
<a class="btn btn-success"
href="{% url 'admin:ak_csv_export' event_slug=event.slug %}">{% trans "Export AKs as CSV" %}</a>
<a class="btn btn-success"
......
......@@ -92,7 +92,7 @@ class AKCategoryViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListMo
return AKCategory.objects.filter(event=self.event)
class AKTrackViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
class AKTrackViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
serializer_class = AKTrackSerializer
......@@ -100,7 +100,7 @@ class AKTrackViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModel
return AKTrack.objects.filter(event=self.event)
class AKViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
class AKViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
serializer_class = AKSerializer
......
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-17 23:56+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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: 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
msgid "Name of new ak track"
msgstr "Name des neuen AK-Tracks"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:142
msgid "Could not create ak track"
msgstr "Konnte neuen AK-Track nicht anlegen"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:168
msgid "Could not update ak track name"
msgstr "Konnte Namen des AK-Tracks nicht ändern"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:174
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
msgid "Could not delete ak track"
msgstr "AK-Track konnte nicht gelöscht werden"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:200
msgid "Manage AK Tracks"
msgstr "AK-Tracks verwalten"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:201
msgid "Add ak track"
msgstr "AK-Track hinzufügen"
#: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:206
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)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:94
msgid "Day (Vertical)"
msgstr "Tag (vertikal)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:105
msgid "Event (Horizontal)"
msgstr "Event (horizontal)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:114
msgid "Event (Vertical)"
msgstr "Event (vertikal)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:141
msgid "Room"
msgstr "Raum"
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:7
msgid "Unscheduled AK Slots"
msgstr "Noch nicht geschedulte AK-Slots"
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:11
msgid "Count"
msgstr "Anzahl"
{% 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 src="{% static "common/vendor/sortable/sortable.min.js" %}"></script>
<script src="{% static "common/vendor/sortable/jquery-sortable.js" %}"></script>
<style>
.ak-list {
padding-left: 5px;
user-select: none;
height: 100%;
}
.ak-list > li {
cursor: move;
}
.track-delete {
cursor: pointer;
}
</style>
<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);
}
}
});
function mark_dirty(container) {
container.removeClass("border-success").addClass("border-warning")
}
function mark_clean(container) {
container.removeClass("border-warning").addClass("border-success");
}
function update_ak_track(ak_id, track_id, container) {
mark_dirty(container);
$.ajax({
url: "{% url "model:AK-list" event_slug=event.slug %}" + ak_id + "/",
type: 'PATCH',
data: {
track: track_id,
},
success: function (response) {
mark_clean(container);
},
error: function (response) {
alert("ERROR. Did not update " + changeInfo.event.title)
}
});
}
sortable_options = {
"group": 'ak-lists',
'sort': false,
// Element is dropped into the list from another list
onAdd: function (/**Event*/evt) {
// same properties as onEnd
console.log(evt.item);
var ak_id = evt.item.dataset["akId"];
var container = $(evt.to).parents(".track-container");
if(evt.to.dataset["sync"]==="true")
{
var track_id = evt.to.dataset["trackId"]
update_ak_track(ak_id, track_id, container);
}
else {
update_ak_track(ak_id, "");
}
},
};
$('.ak-list').sortable(sortable_options);
// Display tooltips containing the tags for each list item (if available)
$('.ak-list li').each(function() {
$(this).tooltip({title: $(this).attr('data-title'), trigger: 'hover'});
});
// Add a new track container (and make usable for dragging)
$('#btn-add-track').click(function () {
var new_track_name = prompt("{% trans 'Name of new ak track' %}");
$.ajax({
url: "{% url "model:AKTrack-list" event_slug=event.slug %}",
type: 'POST',
data: {
name: new_track_name,
event: "{{ event.pk }}"
},
success: function (response) {
console.log(response);
$('<div class="card border-success mb-3 track-container" style="width: 20rem;margin-right:20px;margin-bottom: 20px;"><div class="card-header"><span class="btn btn-danger float-right track-delete" data-track-id="' + response["id"] + '">{% fa5_icon "trash" "fas" %}</span><input class="track-name" data-track-id="None" type="text" value="' + response["name"] + '"></div><div class="card-body"><ul data-track-id="' + response["id"] + '" data-name="' + response["name"] + '" data-sync="true" class="ak-list"></ul></div></div>')
.appendTo($("#workspace"))
.find("ul").sortable(sortable_options)
},
error: function (response) {
console.error(response);
alert("{% trans 'Could not create ak track' %}");
}
});
});
$('#workspace')
// React to track name changes
.on('change', '.track-name', function () {
var track_name_field = $(this);
var new_track_name = track_name_field.val();
var track_id = track_name_field.attr("data-track-id");
var container = track_name_field.parents(".track-container")
mark_dirty(container);
$.ajax({
url: "{% url "model:AKTrack-list" event_slug=event.slug %}" + track_id + "/",
type: 'PATCH',
data: {
name: new_track_name,
},
success: function (response) {
console.log(response);
mark_clean(container);
},
error: function (response) {
console.error(response);
alert("{% trans 'Could not update ak track name' %}");
}
});
})
// Allow to delete a track
.on('click', '.track-delete', function () {
if(confirm("{% trans 'Do you really want to delete this ak track?' %}")) {
var track_delete_button = $(this);
var track_id = track_delete_button.data("trackId");
$.ajax({
url: "{% url "model:AKTrack-list" event_slug=event.slug %}" + track_id + "/",
type: 'DELETE',
data: {},
success: function (response) {
console.log(response);
track_delete_button.parents(".track-container").remove();
},
error: function (response) {
console.error(response);
alert("{% trans 'Could not delete ak track' %}");
}
});
}
});
});
</script>
{% endblock extrahead %}
{% block content %}
<div class="mb-5">
<h3>{{ event }}: {% trans "Manage AK Tracks" %}</h3>
<a id="btn-add-track" href="#" class="btn btn-primary">{% fa5_icon "plus" "fas" %} {% trans "Add ak track" %}</a>
</div>
<div id="workspace" class="row" style="">
<div class="card border-primary mb-3" style="width: 20rem;margin-right:20px;margin-bottom: 20px;">
<div class="card-header">{% trans "AKs without track" %}</div>
<div class="card-body">
<ul data-id="None" data-sync="false" class="ak-list">
{% for ak in aks_without_track %}
<li data-ak-id="{{ ak.pk }}" data-toggle="tooltip" data-placement="top" title="" data-title="{{ ak.tags_list }}">
{{ ak.name }} ({{ ak.category }})
</li>
{% endfor %}
</ul>
</div>
</div>
{% for track in tracks %}
<div class="card border-success mb-3 track-container" style="width: 20rem;margin-right:20px;margin-bottom: 20px;">
<div class="card-header">
<span class="btn btn-danger float-right track-delete" data-track-id="{{ track.pk }}">
{% fa5_icon "trash" "fas" %}
</span>
<input class="track-name" data-track-id="{{ track.pk }}" type="text" value="{{ track }}">
</div>
<div class="card-body">
<ul data-track-id="{{ track.pk }}" data-name="{{ track }}" data-sync="true" class="ak-list">
{% for ak in track.ak_set.all %}
<li data-ak-id="{{ ak.pk }}" data-toggle="tooltip" data-placement="top" title="" data-title="{{ ak.tags_list }}">
{{ ak.name }} ({{ ak.category }})
</li>
{% endfor %}
</ul>
</div>
</div>
{% endfor %}
</div>
<a href="{% url 'admin:event_status' event.slug %}">{% trans "Event Status" %}</a>
{% endblock %}
from django.views.generic import ListView
from django.utils.translation import gettext_lazy as _
from AKModel.availability.models import Availability
from AKModel.models import AKSlot
from AKModel.models import AKSlot, AKTrack
from AKModel.views import AdminViewMixin, FilterByEventSlugMixin
......@@ -37,3 +36,14 @@ class SchedulingAdminView(AdminViewMixin, FilterByEventSlugMixin, ListView):
context["end"] = self.event.end
return context
class TrackAdminView(AdminViewMixin, FilterByEventSlugMixin, ListView):
template_name = "admin/AKScheduling/manage_tracks.html"
model = AKTrack
context_object_name = "tracks"
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
context["aks_without_track"] = self.event.ak_set.filter(track=None)
return context
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-11-03 17:40+0000\n"
"POT-Creation-Date: 2021-02-17 23:56+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"
......@@ -34,43 +34,6 @@ msgstr "Virtueller Raum"
msgid "Virtual Rooms"
msgstr "Virtuelle Räume"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:10
msgid "Scheduling for"
msgstr "Scheduling für"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:94
msgid "Day (Horizontal)"
msgstr "Tag (horizontal)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:101
msgid "Day (Vertical)"
msgstr "Tag (vertikal)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:112
msgid "Event (Horizontal)"
msgstr "Event (horizontal)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:121
msgid "Event (Vertical)"
msgstr "Event (vertikal)"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:148
msgid "Room"
msgstr "Raum"
#: AKScheduling/templates/admin/AKScheduling/scheduling.html:204
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:34
msgid "Event Status"
msgstr "Event-Status"
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:7
msgid "Unscheduled AK Slots"
msgstr "Noch nicht geschedulte AK-Slots"
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:11
msgid "Count"
msgstr "Anzahl"
#: templates/base.html:29
msgid ""
"Are you sure you want to change the language now? This will clear the form!"
......@@ -83,3 +46,30 @@ msgstr "Impressum"
#: templates/base.html:102
msgid "This software is open source"
msgstr "Diese Software ist Open Source"
#~ msgid "Scheduling for"
#~ msgstr "Scheduling für"
#~ msgid "Event Status"
#~ msgstr "Event-Status"
#~ msgid "Day (Horizontal)"
#~ msgstr "Tag (horizontal)"
#~ msgid "Day (Vertical)"
#~ msgstr "Tag (vertikal)"
#~ msgid "Event (Horizontal)"
#~ msgstr "Event (horizontal)"
#~ msgid "Event (Vertical)"
#~ msgstr "Event (vertikal)"
#~ msgid "Room"
#~ msgstr "Raum"
#~ msgid "Unscheduled AK Slots"
#~ msgstr "Noch nicht geschedulte AK-Slots"
#~ msgid "Count"
#~ msgstr "Anzahl"
This diff is collapsed.
This diff is collapsed.
(function (factory) {
"use strict";
var sortable,
jq,
_this = this
;
if (typeof define === "function" && define.amd) {
try {
define(["sortablejs", "jquery"], function(Sortable, $) {
sortable = Sortable;
jq = $;
checkErrors();
factory(Sortable, $);
});
} catch(err) {
checkErrors();
}
return;
} else if (typeof exports === 'object') {
try {
sortable = require('sortablejs');
jq = require('jquery');
} catch(err) { }
}
if (typeof jQuery === 'function' || typeof $ === 'function') {
jq = jQuery || $;
}
if (typeof Sortable !== 'undefined') {
sortable = Sortable;
}
function checkErrors() {
if (!jq) {
throw new Error('jQuery is required for jquery-sortablejs');
}
if (!sortable) {
throw new Error('SortableJS is required for jquery-sortablejs (https://github.com/SortableJS/Sortable)');
}
}
checkErrors();
factory(sortable, jq);
})(function (Sortable, $) {
"use strict";
$.fn.sortable = function (options) {
var retVal,
args = arguments;
this.each(function () {
var $el = $(this),
sortable = $el.data('sortable');
if (!sortable && (options instanceof Object || !options)) {
sortable = new Sortable(this, options);
$el.data('sortable', sortable);
} else if (sortable) {
if (options === 'destroy') {
sortable.destroy();
$el.removeData('sortable');
} else if (options === 'widget') {
retVal = sortable;
} else if (typeof sortable[options] === 'function') {
retVal = sortable[options].apply(sortable, [].slice.call(args, 1));
} else if (options in sortable.options) {
retVal = sortable.option.apply(sortable, args);
}
}
});
return (retVal === void 0) ? this : retVal;
};
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment