Add timeline view for ticket queries

This commit is contained in:
Timothy Hobbs 2019-10-21 19:21:22 +02:00
parent c4a1b9ed66
commit 6eee6d196c
3 changed files with 137 additions and 40 deletions

View File

@ -30,58 +30,110 @@
{% block helpdesk_body %} {% block helpdesk_body %}
{% load in_list %} {% load in_list %}
<div class="card mb-3"> <div class="card">
<div class="card-header"> <div class="card-header">
<i class="fas fa-table"></i> <ul class="nav nav-tabs">
{% trans "Query Results" %} <li class="nav-item" style="width: 200px;">
{% trans "Query Results" %}:
</li>
<li class="nav-item"">
<a class="nav-link active" href="#datatabletabcontents" id="datatabletabcontents-tab" data-toggle="tab" role="tab" aria-controls="datatabletabcontents" aria-selected=true>
<i class="fas fa-th-list"></i>
{% trans "Table" %}
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#timelinetabcontents" id="timelinetabcontents-tab" data-toggle="tab" role="tab" aria-controls="timelinetabcontents" aria-selected=false>
<i class="fas fa-history"></i>
{% trans "Timeline" %}
</a>
</li>
</ul>
</div> </div>
<div class="card-body"> <div class="card-body">
{{ search_message|safe }} {{ search_message|safe }}
<form method='post' action='{% url 'helpdesk:mass_update' %}' id="ticket_mass_update"> <div class="tab-content" id="myTabContent">
<table width="100%" class="table table-sm table-striped table-bordered table-hover" id="ticketTable" data-page-length='{{ default_tickets_per_page }}'> <div class="tab-pane fade show active" id="datatabletabcontents" role="tabpanel" aria-labelledby="datatabletabcontents-tab">
<thead class="thead-light"> <form method='post' action='{% url 'helpdesk:mass_update' %}' id="ticket_mass_update">
<tr> <table width="100%" class="table table-sm table-striped table-bordered table-hover" id="ticketTable" data-page-length='{{ default_tickets_per_page }}'>
<th>&nbsp;</th> <thead class="thead-light">
<th>{% trans "Ticket" %}</th> <tr>
<th>{% trans "Prority" %}</th> <th>&nbsp;</th>
<th>{% trans "Queue" %}</th> <th>{% trans "Ticket" %}</th>
<th>{% trans "Status" %}</th> <th>{% trans "Prority" %}</th>
<th>{% trans "Created" %}</th> <th>{% trans "Queue" %}</th>
<th>{% trans "Due Date" %}</th> <th>{% trans "Status" %}</th>
<th>{% trans "Owner" %}</th> <th>{% trans "Created" %}</th>
<th>{% trans "Time Spent" %}</th> <th>{% trans "Due Date" %}</th>
</tr> <th>{% trans "Owner" %}</th>
</thead> <th>{% trans "Time Spent" %}</th>
</table> </tr>
</thead>
</table>
<p><label>{% trans "Select:" %} </label> <p><label>{% trans "Select:" %} </label>
<button id="select_all_btn" type="button" class="btn btn-primary btn-sm" /> <button id="select_all_btn" type="button" class="btn btn-primary btn-sm" />
<i class="fas fa-check-circle"></i>&nbsp;{% trans "All" %} <i class="fas fa-check-circle"></i>&nbsp;{% trans "All" %}
</button> </button>
<button id='select_none_btn' type="button" class="btn btn-primary btn-sm"><i class="fas fa-times-circle"></i>&nbsp;{% trans "None" %}</button> <button id='select_none_btn' type="button" class="btn btn-primary btn-sm"><i class="fas fa-times-circle"></i>&nbsp;{% trans "None" %}</button>
<button id='select_inverse_btn' type="button" class="btn btn-primary btn-sm"><i class="fas fa-expand-arrows-alt"></i>&nbsp;{% trans "Invert" %}</button> <button id='select_inverse_btn' type="button" class="btn btn-primary btn-sm"><i class="fas fa-expand-arrows-alt"></i>&nbsp;{% trans "Invert" %}</button>
</p> </p>
<p> <p>
<label for='id_mass_action'>{% trans "With Selected Tickets:" %}</label> <label for='id_mass_action'>{% trans "With Selected Tickets:" %}</label>
<select name='action' id='id_mass_action'> <select name='action' id='id_mass_action'>
<option value='take'>{% trans "Take (Assign to me)" %}</option> <option value='take'>{% trans "Take (Assign to me)" %}</option>
<option value='delete'>{% trans "Delete" %}</option> <option value='delete'>{% trans "Delete" %}</option>
<optgroup label='{% trans "Close" %}'> <optgroup label='{% trans "Close" %}'>
<option value='close'>{% trans "Close (Don't Send E-Mail)" %}</option> <option value='close'>{% trans "Close (Don't Send E-Mail)" %}</option>
<option value='close_public'>{% trans "Close (Send E-Mail)" %}</option> <option value='close_public'>{% trans "Close (Send E-Mail)" %}</option>
</optgroup> </optgroup>
<optgroup label='{% trans "Assign To" %}'> <optgroup label='{% trans "Assign To" %}'>
<option value='unassign'>{% trans "Nobody (Unassign)" %}</option> <option value='unassign'>{% trans "Nobody (Unassign)" %}</option>
{% for u in user_choices %}<option value='assign_{{ u.id }}'>{{ u.get_username }}</option>{% endfor %} {% for u in user_choices %}<option value='assign_{{ u.id }}'>{{ u.get_username }}</option>{% endfor %}
</optgroup> </optgroup>
</select> </select>
<button type="submit" class="btn btn-primary btn-sm"><i class="fas fa-arrow-circle-right"></i>&nbsp;{% trans "Go" %}</button> <button type="submit" class="btn btn-primary btn-sm"><i class="fas fa-arrow-circle-right"></i>&nbsp;{% trans "Go" %}</button>
</p> </p>
{% csrf_token %}</form> {% csrf_token %}</form>
</div>
<div class="tab-pane fade" id="timelinetabcontents" role="tabpanel" aria-labelledby="timelinetabcontents-tab">
<div id='timeline-embed' style="width: 100%; height: 80vh"></div>
<!-- 1 -->
<link title="timeline-styles" rel="stylesheet" href="https://cdn.knightlab.com/libs/timeline3/latest/css/timeline.css">
<!-- 2 -->
<script src="https://cdn.knightlab.com/libs/timeline3/latest/js/timeline.js"></script>
<!-- 3 -->
<script type="text/javascript">
// The TL.Timeline constructor takes at least two arguments:
// the id of the Timeline container (no '#'), and
// the URL to your JSON data file or Google spreadsheet.
// the id must refer to an element "above" this code,
// and the element must have CSS styling to give it width and height
// optionally, a third argument with configuration options can be passed.
// See below for more about options.
var timeline_loaded = false;
$(function () {
$('#timelinetabcontents-tab').on('shown.bs.tab', function (e) {
if(!timeline_loaded){
timeline = new TL.Timeline(
'timeline-embed',
'{% url 'helpdesk:timeline_ticket_list' urlsafe_query %}',
)
timeline_loaded = true;
}
});
})
</script>
</div>
</div>
</div> </div>
<!-- /.panel-body --> <!-- /.panel-body -->
</div> </div>

View File

@ -151,6 +151,11 @@ urlpatterns = [
url(r'^datatables_ticket_list/(?P<query>{})$'.format(base64_pattern), url(r'^datatables_ticket_list/(?P<query>{})$'.format(base64_pattern),
staff.datatables_ticket_list, staff.datatables_ticket_list,
name="datatables_ticket_list"), name="datatables_ticket_list"),
url(r'^timeline_ticket_list/(?P<query>{})$'.format(base64_pattern),
staff.timeline_ticket_list,
name="timeline_ticket_list"),
] ]
urlpatterns += [ urlpatterns += [

View File

@ -975,6 +975,46 @@ def datatables_ticket_list(request, query):
return (JsonResponse(result, status=status.HTTP_200_OK)) return (JsonResponse(result, status=status.HTTP_200_OK))
@helpdesk_staff_member_required
@api_view(['GET'])
def timeline_ticket_list(request, query):
"""
Datatable on ticket_list.html uses this view from to get objects to display
on the table. query_tickets_by_args is at lib.py, DatatablesTicketSerializer is in
serializers.py. The serializers and this view use django-rest_framework methods
"""
tickets = get_query(query, HelpdeskUser(request.user))
events = []
def mk_timeline_date(date):
return {
'year': date.year,
'month': date.month,
'day': date.day,
'hour': date.hour,
'minute': date.minute,
'second': date.second,
'second': date.second,
}
for ticket in tickets:
for followup in ticket.followup_set.all():
event = {
'start_date': mk_timeline_date(followup.date),
'text': {
'headline': ticket.title + '<br/>' + followup.title,
'text': (followup.comment if followup.comment else _('No text')) + '<br/> <a href="%s" class="btn" role="button">%s</a>' %
(reverse('helpdesk:view', kwargs={'ticket_id': ticket.pk}), _("View ticket")),
},
'group': _('Messages'),
}
events.append(event)
result = {
'events': events,
}
return (JsonResponse(result, status=status.HTTP_200_OK))
@helpdesk_staff_member_required @helpdesk_staff_member_required
def edit_ticket(request, ticket_id): def edit_ticket(request, ticket_id):
ticket = get_object_or_404(Ticket, id=ticket_id) ticket = get_object_or_404(Ticket, id=ticket_id)