tickets API changes & search box function

This commit is contained in:
Corban-Lee Jones 2024-01-15 00:27:39 +00:00
parent df82417790
commit 73eeedbb36
6 changed files with 378 additions and 345 deletions

View File

@ -1,10 +1,13 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
from django.urls import path from django.urls import path, include
from . import views
from .views import TicketListApiView, FilterCountApiView
urlpatterns = [ urlpatterns = [
path("ticket/", TicketListApiView.as_view(), name="ticket"), path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
path("filter-counts/", FilterCountApiView.as_view(), name="filter-counts"),
path("tickets/", views.TicketListApiView.as_view(), name="tickets"),
path("filter-counts/", views.FilterCountApiView.as_view(), name="filter-counts"),
] ]

View File

@ -41,7 +41,11 @@ class TicketListApiView(APIView):
permission_classes = [permissions.IsAuthenticated] permission_classes = [permissions.IsAuthenticated]
pagination_class = TicketPaginiation pagination_class = TicketPaginiation
ALLOWED_FILTERS = ("uuid__in", "priority__in", "tags__in", "author__department__in") ALLOWED_FILTERS = ("uuid__in", "priority__in", "tags__in", "author__department__in", "title__contains")
MATCHER_MAP = {
"contains": lambda k, v: {k: v[0]},
"in": lambda k, v: {k: v}
}
# @method_decorator(cache_page(60 * 5)) # @method_decorator(cache_page(60 * 5))
def get(self, request: HttpRequest) -> Response: def get(self, request: HttpRequest) -> Response:
@ -68,7 +72,6 @@ class TicketListApiView(APIView):
serializer.save() serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.data, status=status.HTTP_201_CREATED)
def _get_tickets(self, request: HttpRequest) -> Response: def _get_tickets(self, request: HttpRequest) -> Response:
"""Returns a response containing tickets matching the given filters. """Returns a response containing tickets matching the given filters.
@ -92,16 +95,20 @@ class TicketListApiView(APIView):
queryset = Ticket.objects.all() queryset = Ticket.objects.all()
for key in request.GET.keys(): for key, values in request.GET.lists():
values = request.GET.getlist(key) if key.endswith("[]") else [request.GET.get(key)]
key = key.removesuffix("[]") key = key.removesuffix("[]")
if key not in self.ALLOWED_FILTERS: if key not in self.ALLOWED_FILTERS:
raise KeyError(key) raise KeyError(key)
for value in values: if "all" in values:
if value == "all": continue continue
queryset = queryset.filter(Q(**{key: [value]}))
if not key.endswith("__in"):
values = values[0]
filter_kwargs = {key: values}
queryset = queryset.filter(Q(**filter_kwargs))
tickets = queryset.order_by("-create_timestamp") tickets = queryset.order_by("-create_timestamp")
serializer = TicketSerializer(tickets, many=True) serializer = TicketSerializer(tickets, many=True)

View File

@ -22,7 +22,7 @@
"fields": { "fields": {
"title": "Security Patch Installation", "title": "Security Patch Installation",
"description": "There's a critical security patch that needs to be installed on all workstations to address recent vulnerabilities. Attempted to deploy the patch, but facing challenges on certain machines. Need high-priority assistance to ensure all systems are promptly updated for enhanced security measures.", "description": "There's a critical security patch that needs to be installed on all workstations to address recent vulnerabilities. Attempted to deploy the patch, but facing challenges on certain machines. Need high-priority assistance to ensure all systems are promptly updated for enhanced security measures.",
"author": "291cc4c1-3bb3-4417-aaa6-748606fede77", "author": "4965745e-b82a-4496-80e1-055217a780b0",
"priority": "a680328f-0680-456c-8e26-f594e05989ad", "priority": "a680328f-0680-456c-8e26-f594e05989ad",
"create_timestamp": "2024-01-09T00:09:20Z", "create_timestamp": "2024-01-09T00:09:20Z",
"edit_timestamp": "2024-01-09T00:09:20Z", "edit_timestamp": "2024-01-09T00:09:20Z",
@ -92,7 +92,7 @@
"fields": { "fields": {
"title": "Hardware Malfunction", "title": "Hardware Malfunction",
"description": "The printer on the third floor is not responding. Checked cables and power source, but issue persists. Need assistance to fix the hardware problem.", "description": "The printer on the third floor is not responding. Checked cables and power source, but issue persists. Need assistance to fix the hardware problem.",
"author": "291cc4c1-3bb3-4417-aaa6-748606fede77", "author": "4965745e-b82a-4496-80e1-055217a780b0",
"priority": "e79687c6-9054-4706-b9a2-34afccfaa7c8", "priority": "e79687c6-9054-4706-b9a2-34afccfaa7c8",
"create_timestamp": "2024-01-09T00:06:58Z", "create_timestamp": "2024-01-09T00:06:58Z",
"edit_timestamp": "2024-01-09T00:44:49Z", "edit_timestamp": "2024-01-09T00:44:49Z",
@ -126,7 +126,7 @@
"fields": { "fields": {
"title": "VPN Connection Issue", "title": "VPN Connection Issue",
"description": "Remote team members are encountering difficulties establishing a VPN connection. This is hindering their ability to access essential resources. Providing detailed information on the error messages received and troubleshooting steps taken so far. Requesting immediate attention to restore seamless VPN functionality.", "description": "Remote team members are encountering difficulties establishing a VPN connection. This is hindering their ability to access essential resources. Providing detailed information on the error messages received and troubleshooting steps taken so far. Requesting immediate attention to restore seamless VPN functionality.",
"author": "291cc4c1-3bb3-4417-aaa6-748606fede77", "author": "4965745e-b82a-4496-80e1-055217a780b0",
"priority": "e79687c6-9054-4706-b9a2-34afccfaa7c8", "priority": "e79687c6-9054-4706-b9a2-34afccfaa7c8",
"create_timestamp": "2024-01-09T00:09:39Z", "create_timestamp": "2024-01-09T00:09:39Z",
"edit_timestamp": "2024-01-09T00:13:27Z", "edit_timestamp": "2024-01-09T00:13:27Z",
@ -143,7 +143,7 @@
"fields": { "fields": {
"title": "IT Training Request", "title": "IT Training Request",
"description": "Requesting IT training sessions for the marketing team to enhance their proficiency in utilizing specific software tools. Providing a detailed outline of the desired training topics and the anticipated benefits for the team. Seeking assistance in scheduling and conducting the training sessions.", "description": "Requesting IT training sessions for the marketing team to enhance their proficiency in utilizing specific software tools. Providing a detailed outline of the desired training topics and the anticipated benefits for the team. Seeking assistance in scheduling and conducting the training sessions.",
"author": "291cc4c1-3bb3-4417-aaa6-748606fede77", "author": "4965745e-b82a-4496-80e1-055217a780b0",
"priority": "0ebc194c-b856-4e4f-9def-cd190d1e8d43", "priority": "0ebc194c-b856-4e4f-9def-cd190d1e8d43",
"create_timestamp": "2024-01-09T00:12:17Z", "create_timestamp": "2024-01-09T00:12:17Z",
"edit_timestamp": "2024-01-09T00:12:17Z", "edit_timestamp": "2024-01-09T00:12:17Z",
@ -190,7 +190,7 @@
"fields": { "fields": {
"title": "Software Update Problem", "title": "Software Update Problem",
"description": "Unable to install the latest software update on my workstation. Getting error code XYZ. Detailed steps attempted are listed in the description.", "description": "Unable to install the latest software update on my workstation. Getting error code XYZ. Detailed steps attempted are listed in the description.",
"author": "291cc4c1-3bb3-4417-aaa6-748606fede77", "author": "4965745e-b82a-4496-80e1-055217a780b0",
"priority": "a680328f-0680-456c-8e26-f594e05989ad", "priority": "a680328f-0680-456c-8e26-f594e05989ad",
"create_timestamp": "2024-01-09T00:06:32Z", "create_timestamp": "2024-01-09T00:06:32Z",
"edit_timestamp": "2024-01-09T00:06:32Z", "edit_timestamp": "2024-01-09T00:06:32Z",

View File

@ -0,0 +1,343 @@
var displayedTicketID = -1;
filters = {};
editor = null;
searchTimeout = null;
loadingTickets = false;
const formControls = [
{
id: "newTitle",
validation: function(element) {
const value = element.val();
return (!element.attr("required") || value.trim() !== "")
},
errorMessage: function(element) {
return "This field is required."
}
}
];
$(document).ready(function() {
// $(".email-list-item").on("click", function() {
// displayTicket(this);
// });
ClassicEditor
.create( document.getElementById("newDesc"), {})
.then( newEditor => {
editor = newEditor;
})
.catch( error => {
console.error(error)
});
$("#searchTickets").keyup(() => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
value = $("#searchTickets").val();
if (value === "") {
delete filters["title__contains"];
return;
}
filters["title__contains"] = value;
loadAllTickets();
}, 500);
})
setupFilter("#filterSidebar .filter-department", "author__department__in");
setupFilter("#filterSidebar .filter-tag", "tags__in")
setupFilter("#filterSidebar .filter-priority", "priority__in")
loadFilterCounts();
loadAllTickets();
});
function setupFilter(selector, key) {
$(selector).each(function () {
var input = $(this).find("input[type=checkbox], input[type=radio]");
var uuid = input.val();
input.on("change", function () {
if (input.is(":checkbox")) {
if ($(this).is(":checked")) {
filters[key] = filters[key] || [];
filters[key].push(uuid);
} else {
// filters[key].splice(filters[key].indexOf(uuid), 1);
filters[key] = filters[key].filter(id => id !== uuid);
if (filters[key].length === 0) {
delete filters[key];
}
}
}
else if (input.is(":radio") && input.is(":checked")) {
filters[key] = [uuid];
}
console.log(JSON.stringify(filters, null, 4));
loadAllTickets();
});
});
}
function validateForm() {
$("#ticketModal form").find(".form-control,.form-select").removeClass("is-valid is-invalid");
$("#ticketModal form .invalid-feedback").text("");
var valid = true;
formControls.forEach(function(control) {
var element = $("#" + control.id);
if (!control.validation(element)) {
element.addClass("is-invalid");
element.siblings(".invalid-feedback").text(control.errorMessage(element));
valid = false;
}
else {
element.addClass("is-valid");
}
});
return valid;
}
$("#ticketModal form").on("submit", function(event) {
event.preventDefault();
if (!validateForm()) {
return;
}
$.ajax({
url: URL_NewTicket,
type: "POST",
dataType: "json",
data: {
csrfmiddlewaretoken: CSRFMiddlewareToken,
title: $("#newTitle").val(),
description: editor.getData(),
author_id: CurrentUserID,
priority_id: $("#newPriority").val(),
tag_ids: $("#newTags").val()
},
success: function(data) {
loadAllTickets();
loadFilterCounts();
},
error: function(data) {
alert(JSON.stringify(data, null, 4))
}
});
});
function getOrdinalSuffix(day) {
if (day >= 11 && day <= 13) {
return day + 'th';
} else {
switch (day % 10) {
case 1: return day + 'st';
case 2: return day + 'nd';
case 3: return day + 'rd';
default: return day + 'th';
}
}
}
function updateFilterCounts(filterType, data) {
$("#filterSidebar .filter-" + filterType).each(function() {
var uuid = $(this).find("input[type=checkbox],input[type=radio]").val();
var count = data[filterType + '_counts'][uuid];
$(this).find(".badge").text(count);
});
}
function loadFilterCounts() {
$.ajax({
url: URL_FilterCounts,
type: "GET",
success: function(data) {
console.log(JSON.stringify(data, null, 4));
updateFilterCounts('priority', data);
updateFilterCounts('tag', data);
updateFilterCounts('department', data);
$("#filterPriorityAll .badge").text(data.ticket_count);
$("#ticketCount").text(data.ticket_count)
},
error: function(data) {
alert(JSON.stringify(data, null, 4))
}
});
}
function loadAllTickets() {
if (loadingTickets === true) {
return;
}
$("#ticketsContainer").empty();
loadingTickets = true;
// alert(JSON.stringify(filters, null, 4));
$.ajax({
url: URL_Tickets,
type: "GET",
dataType: "json",
data: filters,
success: function(data) {
loadingTickets = false;
console.log(JSON.stringify(data, null, 4))
data.forEach(function(ticket) {
var timestamp = new Date(ticket.timestamp);
var formattedTime;
if (ticket.was_yesterday) {
var day = getOrdinalSuffix(timestamp.getDate());
var month = timestamp.toLocaleString('en-GB', { month: 'short' });
var year = timestamp.toLocaleString('en-GB', { year: 'numeric' });
var time = timestamp.toLocaleString('en-GB', { hour: 'numeric', minute: 'numeric' });
// Formatting the final result
var formattedTime = time + ', ' + day + ' ' + month + ' ' + year;
}
else {
var hours = timestamp.getUTCHours();
var minutes = timestamp.getUTCMinutes();
formattedTime = hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
}
if (ticket.is_edited) {
formattedTime += " • edited";
}
var item = $(`
<div class="email-list-item peers fxw-nw p-20 bdB bgcH-grey-100 cur-p" data-ticket-id="${ticket.uuid}" data-author-icon="${ticket.author.icon}">
<div class="peer mR-10">
<img src="${ticket.author.icon}" alt="" class="w-2r h-2r bdrs-50p me-2" style="object-fit: cover;">
</div>
<div class="peer peer-greed ov-h">
<div class="peers ai-c">
<div class="peer peer-greed">
<h6 class="ticket-author">${ticket.author.forename} ${ticket.author.surname}</h6>
</div>
<div class="peer">
<small class="ticket-timestamp">${formattedTime}</small>
</div>
</div>
<h5 class="fsz-def tt-c c-grey-900 ticket-title">${ticket.title}</h5>
<span class="whs-nw w-100 ov-h tov-e d-b ticket-desc">${ticket.description}</span>
</div>
</div>
`);
$("#ticketsContainer").append(item);
});
$(".email-list-item").on("click", function(e) {
e.preventDefault();
displayTicket(this);
$('.email-content').toggleClass('open');
});
},
error: function(data) {
loadingTickets = false;
alert(JSON.stringify(data, null, 4));
console.error(`${data.responseJSON.error}\n${data.responseJSON.detail}`);
}
});
}
function displayTicket(ticketElement) {
ticket = $(ticketElement);
ticketID = ticket.data("ticket-id");
// $(".back-to-mailbox").off("click").on("click", function(event) {
// event.preventDefault();
// $('.email-content').toggleClass('open');
// displayTicket(ticketElement);
// });
if (displayedTicketID === ticketID) {
// displayedTicketID = -1;
return;
}
ticket.siblings().removeClass("bgc-grey-100");
ticket.addClass("bgc-grey-100");
$("#ticketTitle").text("")
$("#ticketDesc").empty();
$("#ticketAuthor").text("");
$("#ticketAuthorImg").hide();
$("#ticketAuthorImg").prop("src", "");
$("#ticketTimestamp").text("");
$("#btnGroupDrop2").hide();
$("#ticketBadges").empty().hide();
displayedTicketID = ticketID;
$.ajax({
url: URL_Tickets,
type: 'get',
dataType: 'json',
data: {
uuid__in: [ticketID]
},
success: function (data) {
console.log(JSON.stringify(data, null, 4));
var ticket = data[0];
var author = ticket.author;
var department = author.department;
var priority = ticket.priority;
$("#ticketTitle").text(ticket.title);
$("#ticketDesc").append($(`<div class="w-100">${ticket.description}</div>`));
$("#ticketAuthor").text(`${author.forename} ${author.surname}`);
$("#ticketAuthorImg").show();
$("#ticketAuthorImg").prop("src", author.icon);
$("#btnGroupDrop2").show();
$("#ticketBadges").show();
$("#ticketBadges").append($(`<div class="badge me-1" style="color: ${priority.colour}; background-color: ${priority.backgroundcolour};">${priority.title} Priority <i class="ti-control-record "></i></div>`));
if (department != null) {
$("#ticketBadges").append($(`<div class="badge bgc-deep-purple-500 me-1">${department.title}</div>`));
}
ticket.tags.forEach(function(tag) {
$("#ticketBadges").append($(`<div class="badge me-1" style="color: ${tag.colour}; background-color: ${tag.backgroundcolour};">${tag.title} <i class="ti-tag"></i></div>`));
});
// timestamp
var timestamp = new Date(ticket.timestamp);
var formattedTime;
if (ticket.was_yesterday) {
var options = { weekday: 'short', day: 'numeric', month: 'short', year: 'numeric' };
formattedTime = timestamp.toLocaleDateString('en-GB', options);
}
else {
var hours = timestamp.getUTCHours();
var minutes = timestamp.getUTCMinutes();
formattedTime = hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
}
if (ticket.is_edited) {
formattedTime += " • edited";
}
$("#ticketTimestamp").text(formattedTime);
},
error: function(message) {
alert(JSON.stringify(message, null, 4));
}
});
}

View File

@ -151,7 +151,7 @@
</div> </div>
<div class="layer w-100"> <div class="layer w-100">
<div class="bdT bdB"> <div class="bdT bdB">
<input type="text" class="form-control m-0 bdw-0 pY-15 pX-20 bdrs-0" placeholder="Search..."> <input type="text" id="searchTickets" class="form-control m-0 bdw-0 pY-15 pX-20 bdrs-0" placeholder="Search...">
</div> </div>
</div> </div>
@ -296,333 +296,14 @@
{% endblock content %} {% endblock content %}
<!-- Specific Page JS goes HERE -->
{% block javascripts %} {% block javascripts %}
<!-- Define Variables -->
<script> <script>
var displayedTicketID = -1; const URL_Tickets = "{% url 'api:tickets' %}";
filters = {}; const URL_NewTicket = "{% url 'ticket-new' %}";
editor = null; const URL_FilterCounts = "{% url 'api:filter-counts' %}";
const CSRFMiddlewareToken = "{{ csrf_token }}";
const formControls = [ const CurrentUserID = "{{ request.user.uuid }}";
{
id: "newTitle",
validation: function(element) {
const value = element.val();
return (!element.attr("required") || value.trim() !== "")
},
errorMessage: function(element) {
return "This field is required."
}
}
];
$(document).ready(function() {
// $(".email-list-item").on("click", function() {
// displayTicket(this);
// });
ClassicEditor
.create( document.getElementById("newDesc"), {})
.then( newEditor => {
editor = newEditor;
})
.catch( error => {
console.error(error)
});
// $("#filterPriorityAll").click(function() {
// delete filters[".filter-priority"];
// loadAllTickets();
// });
setupFilter("#filterSidebar .filter-department", "author__department__in");
setupFilter("#filterSidebar .filter-tag", "tags__in")
setupFilter("#filterSidebar .filter-priority", "priority__in")
loadFilterCounts();
loadAllTickets();
});
function setupFilter(selector, key) {
$(selector).each(function () {
var input = $(this).find("input[type=checkbox], input[type=radio]");
var uuid = input.val();
input.on("change", function () {
if (input.is(":checkbox")) {
if ($(this).is(":checked")) {
filters[key] = filters[key] || [];
filters[key].push(uuid);
} else {
// filters[key].splice(filters[key].indexOf(uuid), 1);
filters[key] = filters[key].filter(id => id !== uuid);
if (filters[key].length === 0) {
delete filters[key];
}
}
}
else if (input.is(":radio") && input.is(":checked")) {
filters[key] = [uuid];
}
console.log(JSON.stringify(filters, null, 4));
loadAllTickets();
});
});
}
function validateForm() {
$("#ticketModal form").find(".form-control,.form-select").removeClass("is-valid is-invalid");
$("#ticketModal form .invalid-feedback").text("");
var valid = true;
formControls.forEach(function(control) {
var element = $("#" + control.id);
if (!control.validation(element)) {
element.addClass("is-invalid");
element.siblings(".invalid-feedback").text(control.errorMessage(element));
valid = false;
}
else {
element.addClass("is-valid");
}
});
return valid;
}
$("#ticketModal form").on("submit", function(event) {
event.preventDefault();
if (!validateForm()) {
return;
}
$.ajax({
url: "{% url 'ticket-new' %}",
type: "POST",
dataType: "json",
data: {
csrfmiddlewaretoken: "{{ csrf_token }}",
title: $("#newTitle").val(),
description: editor.getData(),
author_id: "{{ request.user.uuid }}",
priority_id: $("#newPriority").val(),
tag_ids: $("#newTags").val()
},
success: function(data) {
loadAllTickets();
loadFilterCounts();
},
error: function(data) {
alert(JSON.stringify(data, null, 4))
}
});
});
function getOrdinalSuffix(day) {
if (day >= 11 && day <= 13) {
return day + 'th';
} else {
switch (day % 10) {
case 1: return day + 'st';
case 2: return day + 'nd';
case 3: return day + 'rd';
default: return day + 'th';
}
}
}
function updateFilterCounts(filterType, data) {
$("#filterSidebar .filter-" + filterType).each(function() {
var uuid = $(this).find("input[type=checkbox],input[type=radio]").val();
var count = data[filterType + '_counts'][uuid];
$(this).find(".badge").text(count);
});
}
function loadFilterCounts() {
$.ajax({
url: "{% url 'api:filter-counts' %}",
type: "GET",
success: function(data) {
console.log(JSON.stringify(data, null, 4));
updateFilterCounts('priority', data);
updateFilterCounts('tag', data);
updateFilterCounts('department', data);
$("#filterPriorityAll .badge").text(data.ticket_count);
$("#ticketCount").text(data.ticket_count)
},
error: function(data) {
alert(JSON.stringify(data, null, 4))
}
});
}
function loadAllTickets() {
$("#ticketsContainer").empty();
// alert(JSON.stringify(filters, null, 4));
$.ajax({
url: "{% url 'api:ticket' %}",
type: "GET",
dataType: "json",
data: filters,
success: function(data) {
console.log(JSON.stringify(data, null, 4))
data.forEach(function(ticket) {
var timestamp = new Date(ticket.timestamp);
var formattedTime;
if (ticket.was_yesterday) {
var day = getOrdinalSuffix(timestamp.getDate());
var month = timestamp.toLocaleString('en-GB', { month: 'short' });
var year = timestamp.toLocaleString('en-GB', { year: 'numeric' });
var time = timestamp.toLocaleString('en-GB', { hour: 'numeric', minute: 'numeric' });
// Formatting the final result
var formattedTime = time + ', ' + day + ' ' + month + ' ' + year;
}
else {
var hours = timestamp.getUTCHours();
var minutes = timestamp.getUTCMinutes();
formattedTime = hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
}
if (ticket.is_edited) {
formattedTime += " • edited";
}
var item = $(`
<div class="email-list-item peers fxw-nw p-20 bdB bgcH-grey-100 cur-p" data-ticket-id="${ticket.uuid}" data-author-icon="${ticket.author.icon}">
<div class="peer mR-10">
<img src="${ticket.author.icon}" alt="" class="w-2r h-2r bdrs-50p me-2" style="object-fit: cover;">
</div>
<div class="peer peer-greed ov-h">
<div class="peers ai-c">
<div class="peer peer-greed">
<h6 class="ticket-author">${ticket.author.forename} ${ticket.author.surname}</h6>
</div>
<div class="peer">
<small class="ticket-timestamp">${formattedTime}</small>
</div>
</div>
<h5 class="fsz-def tt-c c-grey-900 ticket-title">${ticket.title}</h5>
<span class="whs-nw w-100 ov-h tov-e d-b ticket-desc">${ticket.description}</span>
</div>
</div>
`);
$("#ticketsContainer").append(item);
});
$(".email-list-item").on("click", function(e) {
e.preventDefault();
displayTicket(this);
$('.email-content').toggleClass('open');
});
},
error: function(data) {
alert(JSON.stringify(data, null, 4));
console.error(`${data.responseJSON.error}\n${data.responseJSON.detail}`);
}
});
}
function displayTicket(ticketElement) {
ticket = $(ticketElement);
ticketID = ticket.data("ticket-id");
// $(".back-to-mailbox").off("click").on("click", function(event) {
// event.preventDefault();
// $('.email-content').toggleClass('open');
// displayTicket(ticketElement);
// });
if (displayedTicketID === ticketID) {
// displayedTicketID = -1;
return;
}
ticket.siblings().removeClass("bgc-grey-100");
ticket.addClass("bgc-grey-100");
$("#ticketTitle").text("")
$("#ticketDesc").empty();
$("#ticketAuthor").text("");
$("#ticketAuthorImg").hide();
$("#ticketAuthorImg").prop("src", "");
$("#ticketTimestamp").text("");
$("#btnGroupDrop2").hide();
$("#ticketBadges").empty().hide();
displayedTicketID = ticketID;
$.ajax({
url: `{% url 'api:ticket' %}`,
type: 'get',
dataType: 'json',
data: {
uuid__in: [ticketID]
},
success: function (data) {
console.log(JSON.stringify(data, null, 4));
var ticket = data[0];
var author = ticket.author;
var department = author.department;
var priority = ticket.priority;
$("#ticketTitle").text(ticket.title);
$("#ticketDesc").append($(`<div class="w-100">${ticket.description}</div>`));
$("#ticketAuthor").text(`${author.forename} ${author.surname}`);
$("#ticketAuthorImg").show();
$("#ticketAuthorImg").prop("src", author.icon);
$("#btnGroupDrop2").show();
$("#ticketBadges").show();
$("#ticketBadges").append($(`<div class="badge me-1" style="color: ${priority.colour}; background-color: ${priority.backgroundcolour};">${priority.title} Priority <i class="ti-control-record "></i></div>`));
if (department != null) {
$("#ticketBadges").append($(`<div class="badge bgc-deep-purple-500 me-1">${department.title}</div>`));
}
ticket.tags.forEach(function(tag) {
$("#ticketBadges").append($(`<div class="badge me-1" style="color: ${tag.colour}; background-color: ${tag.backgroundcolour};">${tag.title} <i class="ti-tag"></i></div>`));
});
// timestamp
var timestamp = new Date(ticket.timestamp);
var formattedTime;
if (ticket.was_yesterday) {
var options = { weekday: 'short', day: 'numeric', month: 'short', year: 'numeric' };
formattedTime = timestamp.toLocaleDateString('en-GB', options);
}
else {
var hours = timestamp.getUTCHours();
var minutes = timestamp.getUTCMinutes();
formattedTime = hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
}
if (ticket.is_edited) {
formattedTime += " • edited";
}
$("#ticketTimestamp").text(formattedTime);
},
error: function(message) {
alert(JSON.stringify(message, null, 4));
}
});
}
</script> </script>
<script src="{{ ASSETS_ROOT }}/js/tickets.js"></script>
{% endblock javascripts %} {% endblock javascripts %}

View File

@ -6,8 +6,7 @@ from django.conf.urls.static import static
from django.urls import path, include # add this from django.urls import path, include # add this
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), # Django admin route path('admin/', admin.site.urls),
path("api-auth/", include("rest_framework.urls")),
path("api/", include(("apps.api.urls", "apps.api"), namespace="api")), path("api/", include(("apps.api.urls", "apps.api"), namespace="api")),
# ADD NEW Routes HERE # ADD NEW Routes HERE