Compare commits

..

2 Commits

Author SHA1 Message Date
3e17050c40 fead: added kurs column and filter 2025-06-04 23:08:34 +02:00
63a66f6d3e fix: stored js in static folder 2025-06-04 22:35:01 +02:00
4 changed files with 188 additions and 124 deletions

View File

@@ -0,0 +1,68 @@
function initializeTicketDetail(config) {
// Course-Tutor Mapping
if (config.canEdit) {
const courseSelect = document.getElementById('id_course');
const tutorText = document.getElementById('tutor_text');
const tutorDisplay = document.getElementById('tutor_display');
if (courseSelect && config.courseTutorMap) {
courseSelect.addEventListener('change', function() {
const selectedCourseId = this.value;
if (selectedCourseId && config.courseTutorMap[selectedCourseId]) {
tutorText.textContent = config.courseTutorMap[selectedCourseId];
tutorDisplay.classList.remove('bg-gray-100');
tutorDisplay.classList.add('bg-blue-50');
} else if (selectedCourseId) {
tutorText.textContent = 'Kein Tutor zugewiesen';
tutorDisplay.classList.remove('bg-blue-50');
tutorDisplay.classList.add('bg-gray-100');
}
});
}
}
// Answer Field Toggle (nur für Tutoren)
if (config.canEdit && !config.isCreator) {
const statusSelect = document.querySelector('select[name="status"]');
const answerField = document.querySelector('textarea[name="answer"]');
const answerLabel = answerField?.previousElementSibling;
function toggleAnswerField() {
if (!answerField) return;
if (statusSelect.value === 'resolved') {
answerField.disabled = false;
answerField.classList.remove('bg-gray-100', 'cursor-not-allowed');
answerField.classList.add('bg-white');
answerField.required = true;
if (answerLabel && !answerLabel.querySelector('.text-red-500')) {
answerLabel.innerHTML = answerLabel.textContent + ' <span class="text-red-500">*</span>';
}
} else {
answerField.disabled = true;
answerField.classList.add('bg-gray-100', 'cursor-not-allowed');
answerField.classList.remove('bg-white');
answerField.required = false;
if (answerLabel) {
answerLabel.innerHTML = answerLabel.textContent.replace(' *', '');
}
}
}
if (statusSelect && answerField) {
toggleAnswerField();
statusSelect.addEventListener('change', toggleAnswerField);
}
}
}
// Initialisierung wenn DOM geladen
document.addEventListener('DOMContentLoaded', function() {
// Config wird vom Template bereitgestellt
if (window.ticketDetailConfig) {
initializeTicketDetail(window.ticketDetailConfig);
}
});

View File

@@ -1,4 +1,5 @@
{% extends "ticketsystem/base.html" %} {% extends "ticketsystem/base.html" %}
{% load static %}
{% block content %} {% block content %}
<!-- Messages --> <!-- Messages -->
{% if messages %} {% if messages %}
@@ -75,7 +76,7 @@
{% if form.status.errors %}<div class="text-red-600 text-sm mt-1">{{ form.status.errors }}</div>{% endif %} {% if form.status.errors %}<div class="text-red-600 text-sm mt-1">{{ form.status.errors }}</div>{% endif %}
</div> </div>
<div> <div>
<label class="block text-sm font-medium mb-1">Priorität:</label> <label class="block text-sm font-medium mb-1">Fehlerart:</label>
<select name="mistake" <select name="mistake"
{% if not view.can_edit or form.mistake.field.disabled %}disabled{% endif %} {% if not view.can_edit or form.mistake.field.disabled %}disabled{% endif %}
class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {% if not view.can_edit or form.mistake.field.disabled %}bg-gray-100{% endif %}"> class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {% if not view.can_edit or form.mistake.field.disabled %}bg-gray-100{% endif %}">
@@ -119,12 +120,12 @@
<!-- Bearbeitbares Feld --> <!-- Bearbeitbares Feld -->
<textarea name="answer" <textarea name="answer"
rows="4" rows="4"
{% if not view.can_edit or ticket.status != 'resolved' %}disabled{% endif %} {% if not view.can_edit or form.answer.field.disabled %}disabled{% endif %}
placeholder="Beschreibe die Lösung des Problems..." placeholder="Beschreibe die Lösung des Problems..."
class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-black {% if not view.can_edit or ticket.status != 'resolved' %}bg-gray-100 cursor-not-allowed{% endif %}">{{ ticket.answer|default:'' }}</textarea> class="w-full p-2 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-gray-900 {% if not view.can_edit or ticket.status != 'resolved' or form.answer.field.disabled %}bg-gray-100 cursor-not-allowed{% endif %}">{{ ticket.answer|default:'' }}</textarea>
{% if form.answer.errors %}<div class="text-red-600 text-sm mt-1">{{ form.answer.errors }}</div>{% endif %} {% if form.answer.errors %}<div class="text-red-600 text-sm mt-1">{{ form.answer.errors }}</div>{% endif %}
<p class="text-xs text-gray-500 mt-1"> <p class="text-xs text-gray-500 mt-1">
{% if ticket.status != 'resolved' or ticket.status != 'closed' %} {% if ticket.status != 'resolved' %}
Eine Antwort ist erforderlich beim Setzen des Status auf "Gelöst" Eine Antwort ist erforderlich beim Setzen des Status auf "Gelöst"
{% endif %} {% endif %}
</p> </p>
@@ -197,70 +198,16 @@
</div> </div>
</div> </div>
<!-- JavaScript für dynamische Tutor-Anzeige --> <!-- JavaScript für dynamische Tutor-Anzeige -->
<script src="{% static 'js/ticket_detail.js' %}"></script>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { window.ticketDetailConfig = {
const courseSelect = document.getElementById('id_course'); canEdit: {% if view.can_edit %}true{% else %}false{% endif %},
const tutorText = document.getElementById('tutor_text'); isCreator: {% if is_creator %}true{% else %}false{% endif %},
const tutorDisplay = document.getElementById('tutor_display'); courseTutorMap: {
// Course-Tutor Mapping
const courseTutorMap = {
{% for course in form.course.field.queryset %} {% for course in form.course.field.queryset %}
{% if course.tutor %}'{{ course.pk }}': '{{ course.tutor.username }}',{% endif %} {% if course.tutor %}'{{ course.pk }}': '{{ course.tutor.username }}',{% endif %}
{% endfor %} {% endfor %}
};
// Nur aktivieren wenn User bearbeiten kann
{% if view.can_edit %}
courseSelect.addEventListener('change', function() {
const selectedCourseId = this.value;
if (selectedCourseId && courseTutorMap[selectedCourseId]) {
tutorText.textContent = courseTutorMap[selectedCourseId];
tutorDisplay.classList.remove('bg-gray-100');
tutorDisplay.classList.add('bg-blue-50');
} else if (selectedCourseId) {
tutorText.textContent = 'Kein Tutor zugewiesen';
tutorDisplay.classList.remove('bg-blue-50');
tutorDisplay.classList.add('bg-gray-100');
}
});
{% endif %}
});
// Answer Feld nur bei Status "resolved" aktivieren
{% if view.can_edit %}
document.addEventListener('DOMContentLoaded', function() {
const statusSelect = document.querySelector('select[name="status"]');
const answerField = document.querySelector('textarea[name="answer"]');
const answerLabel = answerField.previousElementSibling;
function toggleAnswerField() {
if (statusSelect.value === 'resolved' || statusSelect.value === 'closed') {
answerField.disabled = false;
answerField.classList.remove('bg-gray-100', 'cursor-not-allowed');
answerField.classList.add('bg-white');
answerField.required = true;
// Pflichtfeld-Stern anzeigen
if (!answerLabel.querySelector('.text-red-500')) {
answerLabel.innerHTML = answerLabel.textContent + ' <span class="text-red-500">*</span>';
}
} else {
answerField.disabled = true;
answerField.classList.add('bg-gray-100', 'cursor-not-allowed');
answerField.classList.remove('bg-white');
answerField.required = false;
// Pflichtfeld-Stern entfernen
answerLabel.innerHTML = answerLabel.textContent.replace(' *', '');
}
} }
};
// Initial prüfen
toggleAnswerField();
// Bei Status-Änderung prüfen
statusSelect.addEventListener('change', toggleAnswerField);
});
{% endif %}
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -26,7 +26,7 @@
</div> </div>
<!-- Filter und Suche --> <!-- Filter und Suche -->
<div class="bg-white rounded-lg shadow p-4 mb-6"> <div class="bg-white rounded-lg shadow p-4 mb-6">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-4"> <div class="grid grid-cols-1 lg:grid-cols-5 gap-4">
<!-- Status Filter --> <!-- Status Filter -->
<div> <div>
<form method="get"> <form method="get">
@@ -46,6 +46,7 @@
name="assigned_to" name="assigned_to"
value="{{ request.GET.assigned_to }}"> value="{{ request.GET.assigned_to }}">
{% endif %} {% endif %}
{% if request.GET.course %}<input type="hidden" name="course" value="{{ request.GET.course }}">{% endif %}
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %} {% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
</form> </form>
</div> </div>
@@ -54,18 +55,44 @@
<label class="block text-sm font-medium mb-1">Zuweisung:</label> <label class="block text-sm font-medium mb-1">Zuweisung:</label>
{% if request.GET.assigned_to == user.id|stringformat:'s' %} {% if request.GET.assigned_to == user.id|stringformat:'s' %}
<!-- Wenn aktiv: Button zum Deaktivieren --> <!-- Wenn aktiv: Button zum Deaktivieren -->
<a href="?{% if selected_status %}status={{ selected_status }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}" <a href="?{% if selected_status %}status={{ selected_status }}{% endif %}{% if selected_course %}&course={{ selected_course }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}"
class="block w-full h-10 px-3 border border-purple-300 rounded shadow-sm text-center bg-purple-200 hover:bg-purple-300 transition-colors flex items-center justify-center"> class="block w-full h-10 px-3 border border-purple-300 rounded shadow-sm text-center bg-purple-200 hover:bg-purple-300 transition-colors flex items-center justify-center">
👤 Meine Tickets ✓ 👤 Meine Tickets ✓
</a> </a>
{% else %} {% else %}
<!-- Wenn nicht aktiv: Button zum Aktivieren --> <!-- Wenn nicht aktiv: Button zum Aktivieren -->
<a href="?assigned_to={{ user.id }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}" <a href="?assigned_to={{ user.id }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if selected_course %}&course={{ selected_course }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}"
class="block w-full h-10 px-3 border border-purple-300 rounded shadow-sm text-center bg-purple-50 hover:bg-purple-100 transition-colors flex items-center justify-center"> class="block w-full h-10 px-3 border border-purple-300 rounded shadow-sm text-center bg-purple-50 hover:bg-purple-100 transition-colors flex items-center justify-center">
👤 Meine Tickets 👤 Meine Tickets
</a> </a>
{% endif %} {% endif %}
</div> </div>
<!-- Kurs Filter -->
<div>
<form method="get">
<label class="block text-sm font-medium mb-1">Kurs:</label>
<select name="course"
onchange="this.form.submit()"
class="w-full h-10 px-3 border border-gray-300 rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">Alle Kurse</option>
{% for course in courses %}
<option value="{{ course.id }}"
{% if selected_course == course.id|stringformat:'s' %}selected{% endif %}>
{{ course.code }} - {{ course.name }}
</option>
{% endfor %}
</select>
<!-- Andere Filter beibehalten -->
{% if selected_status %}<input type="hidden" name="status" value="{{ selected_status }}">{% endif %}
{% if selected_course %}<input type="hidden" name="course" value="{{ selected_course }}">{% endif %}
{% if request.GET.assigned_to %}
<input type="hidden"
name="assigned_to"
value="{{ request.GET.assigned_to }}">
{% endif %}
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
</form>
</div>
<!-- Suche --> <!-- Suche -->
<div class="lg:col-span-2"> <div class="lg:col-span-2">
<form method="get"> <form method="get">
@@ -77,6 +104,7 @@
placeholder="Titel oder Beschreibung durchsuchen..." placeholder="Titel oder Beschreibung durchsuchen..."
class="flex-1 h-10 px-3 border border-gray-300 rounded-l shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> class="flex-1 h-10 px-3 border border-gray-300 rounded-l shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
{% if selected_status %}<input type="hidden" name="status" value="{{ selected_status }}">{% endif %} {% if selected_status %}<input type="hidden" name="status" value="{{ selected_status }}">{% endif %}
{% if selected_course %}<input type="hidden" name="course" value="{{ selected_course }}">{% endif %}
{% if request.GET.assigned_to %} {% if request.GET.assigned_to %}
<input type="hidden" <input type="hidden"
name="assigned_to" name="assigned_to"
@@ -117,6 +145,16 @@
class="ml-1 text-green-600 hover:text-green-800">×</a> class="ml-1 text-green-600 hover:text-green-800">×</a>
</span> </span>
{% endif %} {% endif %}
{% if selected_course %}
<span class="px-2 py-1 bg-green-100 text-green-800 text-sm rounded">
Kurs:
{% for course in courses %}
{% if course.id|stringformat:'s' == selected_course %}{{ course.code }}{% endif %}
{% endfor %}
<a href="?{% if selected_status %}status={{ selected_status }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}{% if request.GET.assigned_to %}&assigned_to={{ request.GET.assigned_to }}{% endif %}"
class="ml-1 text-green-600 hover:text-green-800">×</a>
</span>
{% endif %}
<a href="{% url 'ticket-list' %}" <a href="{% url 'ticket-list' %}"
class="text-sm text-gray-600 hover:text-gray-800 font-medium">Alle Filter entfernen</a> class="text-sm text-gray-600 hover:text-gray-800 font-medium">Alle Filter entfernen</a>
</div> </div>
@@ -131,6 +169,7 @@
<tr> <tr>
<th class="px-4 py-3 text-center text-sm font-bold">#</th> <th class="px-4 py-3 text-center text-sm font-bold">#</th>
<th class="px-4 py-3 text-left text-sm font-bold">Titel</th> <th class="px-4 py-3 text-left text-sm font-bold">Titel</th>
<th class="px-4 py-3 text-center text-sm font-bold">Kurs</th>
<th class="px-4 py-3 text-center text-sm font-bold">Status</th> <th class="px-4 py-3 text-center text-sm font-bold">Status</th>
<th class="px-4 py-3 text-center text-sm font-bold">Fehlerart</th> <th class="px-4 py-3 text-center text-sm font-bold">Fehlerart</th>
<th class="px-4 py-3 text-left text-sm font-bold">Zugewiesen an</th> <th class="px-4 py-3 text-left text-sm font-bold">Zugewiesen an</th>
@@ -147,6 +186,11 @@
{{ ticket.title }} {{ ticket.title }}
</a> </a>
</td> </td>
<td class="px-4 py-3 text-center text-sm">
<span class="px-2 py-1 bg-white border border-gray-900 rounded-full text-xs font-bold text-gray-900">
{{ ticket.course.code }}
</span>
</td>
<td class="px-4 py-3 text-center"> <td class="px-4 py-3 text-center">
{% if ticket.status == 'new' %} {% if ticket.status == 'new' %}
<span class="px-2 py-1 rounded-full text-xs font-bold bg-blue-500 text-white">{{ ticket.get_status_display }}</span> <span class="px-2 py-1 rounded-full text-xs font-bold bg-blue-500 text-white">{{ ticket.get_status_display }}</span>
@@ -161,61 +205,62 @@
{% elif ticket.status == 'closed' %} {% elif ticket.status == 'closed' %}
<span class="px-2 py-1 rounded-full text-xs font-bold bg-gray-600 text-white">{{ ticket.get_status_display }}</span> <span class="px-2 py-1 rounded-full text-xs font-bold bg-gray-600 text-white">{{ ticket.get_status_display }}</span>
{% endif %} {% endif %}
</td> <td class="px-4 py-3 text-center">
<td class="px-4 py-3 text-center"> <span class="px-2 py-1 rounded-full text-xs font-bold {% if ticket.mistake == 'typo' %}bg-blue-500 {% elif ticket.mistake == 'formatting_issue' %}bg-purple-500 {% elif ticket.mistake == 'missing_content' %}bg-red-500 {% elif ticket.mistake == 'outdated_content' %}bg-orange-500 {% elif ticket.mistake == 'audio_problem' %}bg-green-500 {% elif ticket.mistake == 'video_problem' %}bg-yellow-500 {% elif ticket.mistake == 'other' %}bg-gray-500 {% else %}bg-gray-400 {% endif %} text-white">
<span class="px-2 py-1 rounded-full text-xs font-bold bg-blue-500 text-white">{{ ticket.get_mistake_display }}</span> {{ ticket.get_mistake_display }}
</td> </span>
<td class="px-4 py-3 text-sm text-gray-600"> </td>
{% if ticket.assigned_to %} <td class="px-4 py-3 text-sm text-gray-600">
{{ ticket.assigned_to.username }} {% if ticket.assigned_to %}
{% else %} {{ ticket.assigned_to.username }}
<span class="text-gray-400 italic">Nicht zugewiesen</span> {% else %}
{% endif %} <span class="text-gray-400 italic">Nicht zugewiesen</span>
</td> {% endif %}
<td class="px-4 py-3 text-center text-sm text-gray-500"> </td>
<div>{{ ticket.created_at|date:"d.m.Y" }}</div> <td class="px-4 py-3 text-center text-sm text-gray-500">
<div class="text-xs text-gray-400">{{ ticket.created_at|date:"H:i" }}</div> <div>{{ ticket.created_at|date:"d.m.Y" }}</div>
</td> <div class="text-xs text-gray-400">{{ ticket.created_at|date:"H:i" }}</div>
</tr> </td>
{% endfor %} </tr>
</tbody> {% endfor %}
</table> </tbody>
</div> </table>
<!-- Pagination --> </div>
{% if is_paginated %} <!-- Pagination -->
<div class="mt-6 flex justify-between items-center"> {% if is_paginated %}
<div class="text-sm text-gray-600">Seite {{ page_obj.number }} von {{ page_obj.paginator.num_pages }}</div> <div class="mt-6 flex justify-between items-center">
<div class="flex gap-2"> <div class="text-sm text-gray-600">Seite {{ page_obj.number }} von {{ page_obj.paginator.num_pages }}</div>
{% if page_obj.has_previous %} <div class="flex gap-2">
<a href="?page={{ page_obj.previous_page_number }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}" {% if page_obj.has_previous %}
class="px-3 py-1 border border-gray-300 rounded hover:bg-gray-50">Zurück</a> <a href="?page={{ page_obj.previous_page_number }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}{% if selected_course %}&course={{ selected_course }}{% endif %}"
{% endif %} class="px-3 py-1 border border-gray-300 rounded hover:bg-gray-50">Zurück</a>
{% if page_obj.has_next %} {% endif %}
<a href="?page={{ page_obj.next_page_number }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}" {% if page_obj.has_next %}
class="px-3 py-1 border border-gray-300 rounded hover:bg-gray-50">Weiter</a> <a href="?page={{ page_obj.next_page_number }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}{% if selected_course %}&course={{ selected_course }}{% endif %}"
{% endif %} class="px-3 py-1 border border-gray-300 rounded hover:bg-gray-50">Weiter</a>
{% endif %}
</div>
</div> </div>
{% endif %}
{% else %}
<!-- Keine Tickets -->
<div class="text-center py-12 bg-white rounded-lg shadow">
<div class="text-gray-400 text-6xl mb-4">📋</div>
{% if search_query %}
<h3 class="text-lg font-medium text-gray-900 mb-2">Keine Tickets gefunden</h3>
<p class="text-gray-500 mb-4">
Keine Tickets gefunden für die Suche „<strong>{{ search_query }}</strong>"
</p>
<a href="?" class="text-blue-600 hover:text-blue-800 font-medium">Alle Tickets anzeigen</a>
{% else %}
<h3 class="text-lg font-medium text-gray-900 mb-2">Noch keine Tickets vorhanden</h3>
<p class="text-gray-500 mb-4">Erstelle dein erstes Ticket um loszulegen.</p>
<a href="{% url 'create' %}"
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded font-medium">
Erstes Ticket erstellen
</a>
{% endif %}
</div> </div>
{% endif %} {% endif %}
{% else %} </div>
<!-- Keine Tickets --> {% endblock %}
<div class="text-center py-12 bg-white rounded-lg shadow">
<div class="text-gray-400 text-6xl mb-4">📋</div>
{% if search_query %}
<h3 class="text-lg font-medium text-gray-900 mb-2">Keine Tickets gefunden</h3>
<p class="text-gray-500 mb-4">
Keine Tickets gefunden für die Suche „<strong>{{ search_query }}</strong>"
</p>
<a href="?" class="text-blue-600 hover:text-blue-800 font-medium">Alle Tickets anzeigen</a>
{% else %}
<h3 class="text-lg font-medium text-gray-900 mb-2">Noch keine Tickets vorhanden</h3>
<p class="text-gray-500 mb-4">Erstelle dein erstes Ticket um loszulegen.</p>
<a href="{% url 'create' %}"
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded font-medium">
Erstes Ticket erstellen
</a>
{% endif %}
</div>
{% endif %}
</div>
{% endblock %}

View File

@@ -16,7 +16,7 @@ from reportlab.lib.units import cm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.enums import TA_LEFT, TA_CENTER from reportlab.lib.enums import TA_LEFT, TA_CENTER
from .models import Ticket, TicketHistory, FAQ from .models import Ticket, TicketHistory, FAQ, Course
class HomeView(TemplateView): class HomeView(TemplateView):
@@ -47,23 +47,27 @@ class TicketListView(ListView):
status = self.request.GET.get("status") status = self.request.GET.get("status")
assigned_to = self.request.GET.get("assigned_to") assigned_to = self.request.GET.get("assigned_to")
query = self.request.GET.get("q") query = self.request.GET.get("q")
course = self.request.GET.get("course")
if status: if status:
queryset = queryset.filter(status=status) queryset = queryset.filter(status=status)
if assigned_to: if assigned_to:
queryset = queryset.filter(assigned_to_id=assigned_to) queryset = queryset.filter(assigned_to_id=assigned_to)
if course: # NEU
queryset = queryset.filter(course_id=course)
if query: if query:
queryset = queryset.filter( queryset = queryset.filter(
Q(title__icontains=query) | Q(description__icontains=query) Q(title__icontains=query) | Q(description__icontains=query)
) )
return queryset return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["selected_status"] = self.request.GET.get("status", "") context["selected_status"] = self.request.GET.get("status", "")
context["selected_course"] = self.request.GET.get("course", "")
context["search_query"] = self.request.GET.get("q", "") context["search_query"] = self.request.GET.get("q", "")
context["status_choices"] = Ticket.STATUS_CHOICES context["status_choices"] = Ticket.STATUS_CHOICES
context["courses"] = Course.objects.filter(is_active=True)
return context return context