forked from extern/django-helpdesk
Finish CSS template changes for Ticket page and related properties; includes responsive Ticket list table; styled file input buttons but need to find way to update text for beyond the first input box; added a ticket_attachment_del page to confirm removal of attachment and styled it
This commit is contained in:
parent
a9cb54ce7e
commit
00cdbcf43b
@ -1,5 +1,5 @@
|
|||||||
This file contains license details for 3rd party software which is
|
This file contains license details for 3rd party software which is
|
||||||
distributed with Jutda Helpdesk.
|
distributed with django-helpdesk.
|
||||||
|
|
||||||
1. License for jQuery & jQuery UI
|
1. License for jQuery & jQuery UI
|
||||||
2. License for jQuery UI 'Smoothness' theme
|
2. License for jQuery UI 'Smoothness' theme
|
||||||
|
@ -523,12 +523,11 @@ class UserSettingsForm(forms.Form):
|
|||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
tickets_per_page = forms.IntegerField(
|
tickets_per_page = forms.ChoiceField(
|
||||||
label=_('Number of tickets to show per page'),
|
label=_('Number of tickets to show per page'),
|
||||||
help_text=_('How many tickets do you want to see on the Ticket List page?'),
|
help_text=_('How many tickets do you want to see on the Ticket List page?'),
|
||||||
required=False,
|
required=False,
|
||||||
min_value=1,
|
choices=((10,'10'),(25,'25'),(50,'50'),(100,'100')),
|
||||||
max_value=1000,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
use_email_as_submitter = forms.BooleanField(
|
use_email_as_submitter = forms.BooleanField(
|
||||||
@ -543,6 +542,7 @@ class EmailIgnoreForm(forms.ModelForm):
|
|||||||
exclude = []
|
exclude = []
|
||||||
|
|
||||||
class TicketCCForm(forms.ModelForm):
|
class TicketCCForm(forms.ModelForm):
|
||||||
|
''' Adds either an email address or helpdesk user as a CC on a Ticket. Used for processing POST requests. '''
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(TicketCCForm, self).__init__(*args, **kwargs)
|
super(TicketCCForm, self).__init__(*args, **kwargs)
|
||||||
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_CC:
|
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_CC:
|
||||||
@ -554,6 +554,27 @@ class TicketCCForm(forms.ModelForm):
|
|||||||
model = TicketCC
|
model = TicketCC
|
||||||
exclude = ('ticket',)
|
exclude = ('ticket',)
|
||||||
|
|
||||||
|
class TicketCCUserForm(forms.ModelForm):
|
||||||
|
''' Adds a helpdesk user as a CC on a Ticket '''
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(TicketCCUserForm, self).__init__(*args, **kwargs)
|
||||||
|
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_CC:
|
||||||
|
users = User.objects.filter(is_active=True, is_staff=True).order_by(User.USERNAME_FIELD)
|
||||||
|
else:
|
||||||
|
users = User.objects.filter(is_active=True).order_by(User.USERNAME_FIELD)
|
||||||
|
self.fields['user'].queryset = users
|
||||||
|
class Meta:
|
||||||
|
model = TicketCC
|
||||||
|
exclude = ('ticket','email',)
|
||||||
|
|
||||||
|
class TicketCCEmailForm(forms.ModelForm):
|
||||||
|
''' Adds an email address as a CC on a Ticket '''
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(TicketCCEmailForm, self).__init__(*args, **kwargs)
|
||||||
|
class Meta:
|
||||||
|
model = TicketCC
|
||||||
|
exclude = ('ticket','user',)
|
||||||
|
|
||||||
class TicketDependencyForm(forms.ModelForm):
|
class TicketDependencyForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TicketDependency
|
model = TicketDependency
|
||||||
|
@ -2,6 +2,26 @@
|
|||||||
Bootstrap overrides
|
Bootstrap overrides
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.btn-file {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.btn-file input[type=file] {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
min-width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
font-size: 100px;
|
||||||
|
text-align: right;
|
||||||
|
filter: alpha(opacity=0);
|
||||||
|
opacity: 0;
|
||||||
|
outline: none;
|
||||||
|
background: white;
|
||||||
|
cursor: inherit;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.thumbnail.filterBox {
|
.thumbnail.filterBox {
|
||||||
display: none;
|
display: none;
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -27,10 +27,6 @@
|
|||||||
<!-- MetisMenu CSS -->
|
<!-- MetisMenu CSS -->
|
||||||
<link href="{% static 'helpdesk/vendor/metisMenu/metisMenu.min.css' %}" rel="stylesheet">
|
<link href="{% static 'helpdesk/vendor/metisMenu/metisMenu.min.css' %}" rel="stylesheet">
|
||||||
|
|
||||||
<!-- Custom CSS -->
|
|
||||||
<link href="{% static 'helpdesk/dist/css/sb-admin-2.css' %}" rel="stylesheet">
|
|
||||||
<link rel='stylesheet' href='{% static "helpdesk/helpdesk-extend.css" %}' type='text/css' media="screen" >
|
|
||||||
|
|
||||||
<!-- Morris Charts CSS -->
|
<!-- Morris Charts CSS -->
|
||||||
{% if helpdesk_settings.HELPDESK_USE_CDN %}
|
{% if helpdesk_settings.HELPDESK_USE_CDN %}
|
||||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
|
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
|
||||||
@ -38,6 +34,16 @@
|
|||||||
<link href="{% static 'helpdesk/vendor/morrisjs/morris.css' %}" rel="stylesheet">
|
<link href="{% static 'helpdesk/vendor/morrisjs/morris.css' %}" rel="stylesheet">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- DataTables CSS -->
|
||||||
|
<link href="{% static 'helpdesk/vendor/datatables-plugins/dataTables.bootstrap.css' %}" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- DataTables Responsive CSS -->
|
||||||
|
<link href="{% static 'helpdesk/vendor/datatables-responsive/dataTables.responsive.css' %}" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Custom CSS -->
|
||||||
|
<link href="{% static 'helpdesk/dist/css/sb-admin-2.css' %}" rel="stylesheet">
|
||||||
|
<link rel='stylesheet' href='{% static "helpdesk/helpdesk-extend.css" %}' type='text/css' media="screen" >
|
||||||
|
|
||||||
<!-- Custom Fonts -->
|
<!-- Custom Fonts -->
|
||||||
<link href="{% static 'helpdesk/vendor/font-awesome/css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
|
<link href="{% static 'helpdesk/vendor/font-awesome/css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
@ -47,7 +53,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<script src="{% static 'helpdesk/vendor/jquery/jquery.min.js' %}"></script>
|
<script src="{% static 'helpdesk/vendor/jquery/jquery.min.js' %}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script src='{% static "helpdesk/jquery-ui-1.12.0.min.js" %}' type='text/javascript' language='javascript'></script>
|
<!--<script src='{% static "helpdesk/jquery-ui-1.12.0.min.js" %}' type='text/javascript' language='javascript'></script>-->
|
||||||
|
|
||||||
<!-- Bootstrap Core JavaScript -->
|
<!-- Bootstrap Core JavaScript -->
|
||||||
{% if helpdesk_settings.HELPDESK_USE_CDN %}
|
{% if helpdesk_settings.HELPDESK_USE_CDN %}
|
||||||
@ -56,6 +62,14 @@
|
|||||||
<script src="{% static 'helpdesk/vendor/bootstrap/js/bootstrap.min.js' %}"></script>
|
<script src="{% static 'helpdesk/vendor/bootstrap/js/bootstrap.min.js' %}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- DataTables JavaScript -->
|
||||||
|
<script src="{% static 'helpdesk/vendor/datatables/js/jquery.dataTables.js' %}"></script>
|
||||||
|
<script src="{% static 'helpdesk/vendor/datatables-plugins/dataTables.bootstrap.min.js' %}"></script>
|
||||||
|
<script src="{% static 'helpdesk/vendor/datatables-responsive/dataTables.responsive.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- Custom Theme JavaScript -->
|
||||||
|
<script src="{% static 'helpdesk/dist/js/sb-admin-2.js' %}"></script>
|
||||||
|
|
||||||
<!-- RSS -->
|
<!-- RSS -->
|
||||||
<link rel='alternate' href='{% url 'helpdesk_rss_user' user.get_username %}' type='application/rss+xml' title='{% trans "My Open Tickets" %}' />
|
<link rel='alternate' href='{% url 'helpdesk_rss_user' user.get_username %}' type='application/rss+xml' title='{% trans "My Open Tickets" %}' />
|
||||||
<link rel='alternate' href='{% url 'helpdesk_rss_activity' %}' type='application/rss+xml' title='{% trans "All Recent Activity" %}' />
|
<link rel='alternate' href='{% url 'helpdesk_rss_activity' %}' type='application/rss+xml' title='{% trans "All Recent Activity" %}' />
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
<td><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></td>
|
<td><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></td>
|
||||||
<td>{{ ticket.queue }}</td>
|
<td>{{ ticket.queue }}</td>
|
||||||
<td><span title='{{ ticket.created|date:"r" }}'>{{ ticket.created|naturaltime }}</span></td>
|
<td><span title='{{ ticket.created|date:"r" }}'>{{ ticket.created|naturaltime }}</span></td>
|
||||||
<td><a href='{{ ticket.get_absolute_url }}?take'><span class='button button_take'>{% trans "Take" %}</span></a> | <a href='{% url 'helpdesk_delete' ticket.id %}'><span class='button button_delete'>{% trans "Delete" %}</span></a></td>
|
<td><a href='{{ ticket.get_absolute_url }}?take'><button class='btn btn-primary btn-xs'>{% trans "Take" %}</button></a> | <a href='{% url 'helpdesk_delete' ticket.id %}'><button class='btn btn-danger btn-xs'>{% trans "Delete" %}</button></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan='6'>{% trans "There are no unassigned tickets." %}</td></tr>
|
<tr><td colspan='6'>{% trans "There are no unassigned tickets." %}</td></tr>
|
||||||
|
@ -11,7 +11,6 @@ $(document).ready(function() {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
processAddFileClick();
|
|
||||||
$("#ShowFileUpload").click(function() {
|
$("#ShowFileUpload").click(function() {
|
||||||
$("#FileUpload").fadeIn();
|
$("#FileUpload").fadeIn();
|
||||||
$("#ShowFileUploadPara").hide();
|
$("#ShowFileUploadPara").hide();
|
||||||
@ -28,19 +27,37 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("[data-toggle=tooltip]").tooltip();
|
$("[data-toggle=tooltip]").tooltip();
|
||||||
});
|
|
||||||
|
|
||||||
function processAddFileClick() {
|
// for CSS customized file select/browse button
|
||||||
/* Until jQuery includes some 'livequery' functionality in the core
|
$(':file').on('fileselect', function(event, numFiles, label, browseButtonNum) {
|
||||||
distribution, this will have to do. */
|
$("#selectedfilename"+browseButtonNum).html(label);
|
||||||
$(".AddAnotherFile>a").click(function() {
|
|
||||||
$(this).parent().remove();
|
|
||||||
$("#FileUpload>dl").append("<dt><label>{% trans "Attach another File" %}</label></dt><dd><input type='file' name='attachment' id='file' multiple/> <span class='AddAnotherFile'>(<a href='#'>{% trans "Add Another File" %}</a>)</span></dd>");
|
|
||||||
processAddFileClick();
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
var x = 0;
|
||||||
|
var wrapper = $(".input_fields_wrap"); //Fields wrapper
|
||||||
|
var add_button = $(".add_field_button"); //Add button ID
|
||||||
|
|
||||||
|
$(add_button).click(function(e){ //on add input button click
|
||||||
|
x++;
|
||||||
|
e.preventDefault();
|
||||||
|
$(wrapper).append("<div><label class='btn btn-primary btn-sm btn-file'>Browse... <input type='file' name='attachment' id='file" + x + "' multiple style='display: none;'/></label><span> </span><span id='selectedfilename" + x + "'>{% trans 'No files selected.' %}</span></div>"); //add input box
|
||||||
|
|
||||||
|
$(document).on('change', '#file'+x, function() {
|
||||||
|
var input = $(this),
|
||||||
|
numFiles = input.get(0).files ? input.get(0).files.length : 1,
|
||||||
|
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
|
||||||
|
input.trigger('fileselect', [numFiles, label, x]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('change', '#file0', function() {
|
||||||
|
var input = $(this),
|
||||||
|
numFiles = input.get(0).files ? input.get(0).files.length : 1,
|
||||||
|
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
|
||||||
|
input.trigger('fileselect', [numFiles, label, 0]);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -99,7 +116,7 @@ function processAddFileClick() {
|
|||||||
{% for attachment in followup.attachment_set.all %}{% if forloop.first %}<div class='attachments'><ul>{% endif %}
|
{% for attachment in followup.attachment_set.all %}{% if forloop.first %}<div class='attachments'><ul>{% endif %}
|
||||||
<li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }})
|
<li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }})
|
||||||
{% if followup.user and request.user == followup.user %}
|
{% if followup.user and request.user == followup.user %}
|
||||||
<a href='{% url 'helpdesk_attachment_del' ticket.id attachment.id %}'>delete</a>
|
<a href='{% url 'helpdesk_attachment_del' ticket.id attachment.id %}'><button class="btn btn-danger btn-xs">{% trans 'Delete' %}</button></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% if forloop.last %}</ul></div>{% endif %}
|
{% if forloop.last %}</ul></div>{% endif %}
|
||||||
@ -165,7 +182,7 @@ function processAddFileClick() {
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<p id='ShowFurtherOptPara'><button id='ShowFurtherEditOptions'>{% trans "Change Further Details »" %}</button></p>
|
<p id='ShowFurtherOptPara'><button class="btn btn-warning btn-sm" id='ShowFurtherEditOptions'>{% trans "Change Further Details »" %}</button></p>
|
||||||
|
|
||||||
<div id='FurtherEditOptions' style='display: none;'>
|
<div id='FurtherEditOptions' style='display: none;'>
|
||||||
|
|
||||||
@ -186,21 +203,29 @@ function processAddFileClick() {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p id='ShowFileUploadPara'><button id='ShowFileUpload'>{% trans "Attach File(s) »" %}</button></p>
|
<p id='ShowFileUploadPara'><button class="btn btn-warning btn-sm" id='ShowFileUpload'>{% trans "Attach File(s) »" %}</button></p>
|
||||||
|
|
||||||
<div id='FileUpload' style='display: none;'>
|
<div id='FileUpload' style='display: none;'>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
|
|
||||||
<dt><label for='id_file'>{% trans "Attach a File" %}</label></dt>
|
<dt><label for='id_file'>{% trans "Attach a File" %}</label></dt>
|
||||||
<dd><input type='file' name='attachment' id='file' multiple/> <span class='AddAnotherFile'>(<a href='#'>{% trans "Add Another File" %}</a>)</span></dd>
|
<dd>
|
||||||
|
<div class="input_fields_wrap">
|
||||||
|
<div>
|
||||||
|
<button class="add_field_button btn btn-success btn-xs">{% trans "Add Another File" %}</button>
|
||||||
|
<div><label class='btn btn-primary btn-sm btn-file'>
|
||||||
|
Browse... <input type="file" name='attachment' id='file0' style='display: none;'/>
|
||||||
|
</label><span> </span><span id='selectedfilename0'>{% trans 'No files selected.' %}</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<input class="btn btn-primary" type='submit' value='{% trans "Update This Ticket" %}' />
|
<button class="btn btn-primary btn-lg" type='submit'>{% trans "Update This Ticket" %}</button>
|
||||||
|
|
||||||
{% csrf_token %}</form>
|
{% csrf_token %}</form>
|
||||||
|
|
||||||
|
16
helpdesk/templates/helpdesk/ticket_attachment_del.html
Normal file
16
helpdesk/templates/helpdesk/ticket_attachment_del.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}{% load i18n %}
|
||||||
|
|
||||||
|
{% block helpdesk_title %}{% trans "Delete Ticket Attachment" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}{% blocktrans %}
|
||||||
|
<h2>Delete Ticket Attachment</h2>
|
||||||
|
|
||||||
|
<p>Are you sure you wish to delete the attachment <i>{{ filename }}</i> from this ticket? The attachment data will be permanently deleted from the database, but the attachment itself will still exist on the server.</p>
|
||||||
|
{% endblocktrans %}
|
||||||
|
|
||||||
|
<p><a href='../../'><button class="btn btn-primary btn-lg">{% trans "Don't Delete" %}</button></a></p>
|
||||||
|
|
||||||
|
<form method='post' action='./'>
|
||||||
|
<button class="btn btn-danger" type='submit'>{% trans "Yes, I Understand - Delete" %} {{ filename }}</button>
|
||||||
|
{% csrf_token %}</form>
|
||||||
|
{% endblock %}
|
@ -2,24 +2,62 @@
|
|||||||
|
|
||||||
{% block helpdesk_title %}{% trans "Add Ticket CC" %}{% endblock %}
|
{% block helpdesk_title %}{% trans "Add Ticket CC" %}{% endblock %}
|
||||||
|
|
||||||
{% block helpdesk_body %}{% blocktrans %}
|
{% block helpdesk_body %}
|
||||||
<h2>Add Ticket CC</h2>
|
<h2>{% trans 'Add Ticket CC' %}</h2>
|
||||||
|
|
||||||
<p>To automatically send an email to a user or e-mail address when this ticket is updated, select the user or enter an e-mail address below.</p>{% endblocktrans %}
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading">
|
||||||
|
{% trans 'To automatically send an email to a user or e-mail address when this ticket is updated, select the user or enter an e-mail address below.' %}
|
||||||
|
</div>
|
||||||
|
<!-- /.panel-heading -->
|
||||||
|
<div class="panel-body">
|
||||||
|
<!-- Nav tabs -->
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="active"><a href="#EmailCC" data-toggle="tab">Email</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="#UserCC" data-toggle="tab">User</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<form method='post' action='./'>
|
<!-- Tab panes -->
|
||||||
|
<div class="tab-content">
|
||||||
<fieldset>
|
<div class="tab-pane fade in active" id="EmailCC">
|
||||||
<dl>{% for field in form %}
|
<h4>{% trans 'Add Email' %}</h4>
|
||||||
|
<form method='post' action='./'>
|
||||||
|
<fieldset>
|
||||||
|
<dl>{% for field in form_email %}
|
||||||
<dt><label for='id_{{ field.name }}'>{{ field.label }}</label></dt>
|
<dt><label for='id_{{ field.name }}'>{{ field.label }}</label></dt>
|
||||||
<dd>{{ field }}</dd>
|
<dd>{{ field }}</dd>
|
||||||
{% if field.errors %}<dd class='error'>{{ field.errors }}</dd>{% endif %}
|
{% if field.errors %}<dd class='error'>{{ field.errors }}</dd>{% endif %}
|
||||||
{% if field.help_text %}<dd class='form_help_text'>{{ field.help_text }}</dd>{% endif %}
|
{% if field.help_text %}<dd class='form_help_text'>{{ field.help_text }}</dd>{% endif %}
|
||||||
{% endfor %}</dl>
|
{% endfor %}</dl>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<button class="btn btn-primary" type='submit'>{% trans "Save Ticket CC" %}</button>
|
||||||
<input class="btn btn-primary" type='submit' value='{% trans "Save Ticket CC" %}' />
|
{% csrf_token %}</form>
|
||||||
|
</div>
|
||||||
{% csrf_token %}</form>
|
<div class="tab-pane fade" id="UserCC">
|
||||||
|
<h4>{% trans 'Add User' %}</h4>
|
||||||
|
<form method='post' action='./'>
|
||||||
|
<fieldset>
|
||||||
|
<dl>{% for field in form_user %}
|
||||||
|
<dt><label for='id_{{ field.name }}'>{{ field.label }}</label></dt>
|
||||||
|
<dd>{{ field }}</dd>
|
||||||
|
{% if field.errors %}<dd class='error'>{{ field.errors }}</dd>{% endif %}
|
||||||
|
{% if field.help_text %}<dd class='form_help_text'>{{ field.help_text }}</dd>{% endif %}
|
||||||
|
{% endfor %}</dl>
|
||||||
|
</fieldset>
|
||||||
|
<button class="btn btn-primary" type='submit'>{% trans "Save Ticket CC" %}</button>
|
||||||
|
{% csrf_token %}</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.panel-body -->
|
||||||
|
</div>
|
||||||
|
<!-- /.panel -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.row -->
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
<p>Are you sure you wish to remove the dependency on this ticket?</p>
|
<p>Are you sure you wish to remove the dependency on this ticket?</p>
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
|
||||||
<p><a href='../../'>{% trans "Don't Delete" %}</a></p>
|
<p><a href='../../'><button class="btn btn-primary btn-lg">{% trans "Don't Delete" %}</button></a></p>
|
||||||
|
|
||||||
<form method='post' action='./'><input class="btn btn-primary" type='submit' value='{% trans "Yes, Delete" %}' />{% csrf_token %}</form>
|
<form method='post' action='./'>
|
||||||
|
<button class="btn btn-danger" type='submit'>{% trans "Yes, I Understand - Delete" %}</button>
|
||||||
|
{% csrf_token %}</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
<table class="table table-striped table-bordered table-hover">
|
<table class="table table-striped table-bordered table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class='row_tablehead'><td colspan='2'><h3>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</h3> <span class='ticket_toolbar'>
|
<tr class='row_tablehead'><td colspan='2'><h3>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</h3> <span class='ticket_toolbar'>
|
||||||
<a href='{% url 'helpdesk_edit' ticket.id %}' class="ticket-edit"><i class="fa fa-pencil"></i> {% trans "Edit" %}</a>
|
<a href="{% url 'helpdesk_edit' ticket.id %}" class="ticket-edit"><button class="btn btn-warning btn-xs"><i class="fa fa-pencil"></i> {% trans "Edit" %}</button></a>
|
||||||
| <a href='{% url 'helpdesk_delete' ticket.id %}' class="ticket-delete"><i class="fa fa-trash-o"></i> {% trans "Delete" %}</a>
|
| <a href="{% url 'helpdesk_delete' ticket.id %}" class="ticket-delete"><button class="btn btn-danger btn-xs"><i class="fa fa-trash-o"></i> {% trans "Delete" %}</button></a>
|
||||||
{% if ticket.on_hold %} | <a href='{% url 'helpdesk_unhold' ticket.id %}' class="ticket-hold"><i class="fa fa-play"></i> {% trans "Unhold" %}</a>{% else %} | <a href='{% url 'helpdesk_hold' ticket.id %}' class="ticket-hold"><i class="fa fa-pause"></i> {% trans "Hold" %}</a>{% endif %}
|
{% if ticket.on_hold %} | <a href="{% url 'helpdesk_unhold' ticket.id %}" class="ticket-hold"><button class="btn btn-warning btn-xs"><i class="fa fa-play"></i> {% trans "Unhold" %}</button></a>{% else %} | <a href="{% url 'helpdesk_hold' ticket.id %}" class="ticket-hold"><button class="btn btn-warning btn-xs"><i class="fa fa-pause"></i> {% trans "Hold" %}</button></a>{% endif %}
|
||||||
</span></td></tr>
|
</span></td></tr>
|
||||||
<tr><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
|
<tr><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -3,17 +3,14 @@
|
|||||||
{% load static from staticfiles %}
|
{% load static from staticfiles %}
|
||||||
{% block helpdesk_title %}{% trans "Tickets" %}{% endblock %}
|
{% block helpdesk_title %}{% trans "Tickets" %}{% endblock %}
|
||||||
{% block helpdesk_head %}
|
{% block helpdesk_head %}
|
||||||
|
|
||||||
<script type='text/javascript' language='javascript' src='{% static "helpdesk/filter.js" %}'></script>
|
<script type='text/javascript' language='javascript' src='{% static "helpdesk/filter.js" %}'></script>
|
||||||
<script type='text/javascript' language='javascript'>
|
<script type='text/javascript' language='javascript'>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
// Enable Tabs
|
$('#ticketTable').DataTable({
|
||||||
$("#searchtabs").tabs({
|
responsive: true
|
||||||
collapsible:true
|
|
||||||
});
|
});
|
||||||
// Hide all tabs by default
|
|
||||||
$("#searchtabs > ul > li").removeClass().addClass("ui-corner-top ui-state-default");
|
|
||||||
$("#searchtabs > div").addClass("ui-tabs-hide");
|
|
||||||
|
|
||||||
$("#select_all").click(function() {
|
$("#select_all").click(function() {
|
||||||
$(".ticket_multi_select").attr('checked', true);
|
$(".ticket_multi_select").attr('checked', true);
|
||||||
@ -213,20 +210,21 @@ $(document).ready(function() {
|
|||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
<!-- /.row -->
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="panel panel-success">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
{% trans "Query Results" %} - {{ search_message|safe }}
|
{% trans "Query Results" %} - {{ search_message|safe }}
|
||||||
</div>
|
</div>
|
||||||
<!-- /.panel-heading -->
|
<!-- /.panel-heading -->
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="table-responsive">
|
|
||||||
<form method='post' action='{% url 'helpdesk_mass_update' %}' id="ticket_mass_update">
|
<form method='post' action='{% url 'helpdesk_mass_update' %}' id="ticket_mass_update">
|
||||||
<table class="table table-striped table-bordered table-hover">
|
<table width="100%" class="table table-striped table-bordered table-hover" id="ticketTable" data-page-length='{{ default_tickets_per_page }}'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
|
<th> </th>
|
||||||
<th>{% trans "Pr" %}</th>
|
<th>{% trans "Pr" %}</th>
|
||||||
<th>{% trans "Title" %}</th>
|
<th>{% trans "Title" %}</th>
|
||||||
<th>{% trans "Queue" %}</th>
|
<th>{% trans "Queue" %}</th>
|
||||||
@ -236,7 +234,7 @@ $(document).ready(function() {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for ticket in tickets.object_list %}
|
{% for ticket in tickets %}
|
||||||
<tr class="{{ ticket.get_priority_css_class }}">
|
<tr class="{{ ticket.get_priority_css_class }}">
|
||||||
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></th>
|
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></th>
|
||||||
<td><input type='checkbox' name='ticket_id' value='{{ ticket.id }}' class='ticket_multi_select' /></td>
|
<td><input type='checkbox' name='ticket_id' value='{{ ticket.id }}' class='ticket_multi_select' /></td>
|
||||||
@ -248,34 +246,16 @@ $(document).ready(function() {
|
|||||||
<td>{{ ticket.get_assigned_to }}</td>
|
<td>{{ ticket.get_assigned_to }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan='5'>{% trans "No Tickets Match Your Selection" %}</td></tr>
|
<tr><td colspan='7'>{% trans "No Tickets Match Your Selection" %}</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% csrf_token %}</form>
|
{% csrf_token %}</form>
|
||||||
|
|
||||||
<div class="pagination">
|
|
||||||
<span class="step-links">
|
|
||||||
{% if tickets.has_previous %}
|
|
||||||
<a href="?{% if query_string %}{{ query_string }}&{% endif %}page={{ tickets.previous_page_number }}">{% trans "Previous" %}</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<span class="current">
|
|
||||||
{% blocktrans with tickets.number as ticket_num and tickets.paginator.num_pages as num_pages %}Page {{ ticket_num }} of {{ num_pages }}.{% endblocktrans %}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{% if tickets.has_next %}
|
|
||||||
<a href="?{% if query_string %}{{ query_string }}&{% endif %}page={{ tickets.next_page_number }}">{% trans "Next" %}</a>
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p><label>{% trans "Select:" %} </label> <a href='#select_all' id='select_all'><button class="btn btn-primary btn-sm">{% trans "All" %}</button></a> <a href='#select_none' id='select_none'><button class="btn btn-primary btn-sm">{% trans "None" %}</button></a> <a href='#select_inverse' id='select_inverse'><button class="btn btn-primary btn-sm">{% trans "Invert" %}</button></a></p>
|
<p><label>{% trans "Select:" %} </label> <a href='#select_all' id='select_all'><button class="btn btn-primary btn-sm">{% trans "All" %}</button></a> <a href='#select_none' id='select_none'><button class="btn btn-primary btn-sm">{% trans "None" %}</button></a> <a href='#select_inverse' id='select_inverse'><button class="btn btn-primary btn-sm">{% trans "Invert" %}</button></a></p>
|
||||||
|
|
||||||
<p><label for='id_mass_action'>{% trans "With Selected Tickets:" %}</label> <select name='action' id='id_mass_action'><option value='take'>{% trans "Take (Assign to me)" %}</option><option value='delete'>{% trans "Delete" %}</option><optgroup label='{% trans "Close" %}'><option value='close'>{% trans "Close (Don't Send E-Mail)" %}</option><option value='close_public'>{% trans "Close (Send E-Mail)" %}</option></optgroup><optgroup label='{% trans "Assign To" %}'><option value='unassign'>{% trans "Nobody (Unassign)" %}</option>{% for u in user_choices %}<option value='assign_{{ u.id }}'>{{ u.get_username }}</option>{% endfor %}</optgroup></select> <button class="btn btn-primary btn-sm">{% trans "Go" %}</button></p>
|
<p><label for='id_mass_action'>{% trans "With Selected Tickets:" %}</label> <select name='action' id='id_mass_action'><option value='take'>{% trans "Take (Assign to me)" %}</option><option value='delete'>{% trans "Delete" %}</option><optgroup label='{% trans "Close" %}'><option value='close'>{% trans "Close (Don't Send E-Mail)" %}</option><option value='close_public'>{% trans "Close (Send E-Mail)" %}</option></optgroup><optgroup label='{% trans "Assign To" %}'><option value='unassign'>{% trans "Nobody (Unassign)" %}</option>{% for u in user_choices %}<option value='assign_{{ u.id }}'>{{ u.get_username }}</option>{% endfor %}</optgroup></select> <button class="btn btn-primary btn-sm">{% trans "Go" %}</button></p>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.table-responsive -->
|
|
||||||
</div>
|
|
||||||
<!-- /.panel-body -->
|
<!-- /.panel-body -->
|
||||||
</div>
|
</div>
|
||||||
<!-- /.panel -->
|
<!-- /.panel -->
|
||||||
@ -285,4 +265,5 @@ $(document).ready(function() {
|
|||||||
<!-- /.row -->
|
<!-- /.row -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -38,7 +38,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from datetime import datetime as timezone
|
from datetime import datetime as timezone
|
||||||
|
|
||||||
from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm, EditFollowUpForm, TicketDependencyForm
|
from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm, TicketCCEmailForm, TicketCCUserForm, EditFollowUpForm, TicketDependencyForm
|
||||||
from helpdesk.lib import send_templated_mail, query_to_dict, apply_query, safe_template_context
|
from helpdesk.lib import send_templated_mail, query_to_dict, apply_query, safe_template_context
|
||||||
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC, TicketDependency
|
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC, TicketDependency
|
||||||
from helpdesk import settings as helpdesk_settings
|
from helpdesk import settings as helpdesk_settings
|
||||||
@ -424,12 +424,16 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
files = []
|
files = []
|
||||||
if request.FILES:
|
if request.FILES:
|
||||||
import mimetypes, os
|
import mimetypes, os
|
||||||
|
print(request.FILES)
|
||||||
|
print(request.FILES.getlist('attachment'))
|
||||||
for file in request.FILES.getlist('attachment'):
|
for file in request.FILES.getlist('attachment'):
|
||||||
filename = file.name.encode('ascii', 'ignore')
|
filename = file.name.encode('ascii', 'ignore')
|
||||||
|
filename = filename.decode("utf-8")
|
||||||
|
print(filename)
|
||||||
a = Attachment(
|
a = Attachment(
|
||||||
followup=f,
|
followup=f,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream',
|
mime_type=file.content_type or 'application/octet-stream',
|
||||||
size=file.size,
|
size=file.size,
|
||||||
)
|
)
|
||||||
a.file.save(filename, file, save=False)
|
a.file.save(filename, file, save=False)
|
||||||
@ -826,17 +830,6 @@ def ticket_list(request):
|
|||||||
}
|
}
|
||||||
ticket_qs = apply_query(tickets, query_params)
|
ticket_qs = apply_query(tickets, query_params)
|
||||||
|
|
||||||
ticket_paginator = paginator.Paginator(ticket_qs, request.user.usersettings.settings.get('tickets_per_page') or 20)
|
|
||||||
try:
|
|
||||||
page = int(request.GET.get('page', '1'))
|
|
||||||
except ValueError:
|
|
||||||
page = 1
|
|
||||||
|
|
||||||
try:
|
|
||||||
tickets = ticket_paginator.page(page)
|
|
||||||
except (paginator.EmptyPage, paginator.InvalidPage):
|
|
||||||
tickets = ticket_paginator.page(ticket_paginator.num_pages)
|
|
||||||
|
|
||||||
search_message = ''
|
search_message = ''
|
||||||
if 'query' in context and settings.DATABASES['default']['ENGINE'].endswith('sqlite'):
|
if 'query' in context and settings.DATABASES['default']['ENGINE'].endswith('sqlite'):
|
||||||
search_message = _('<p><strong>Note:</strong> Your keyword search is case sensitive because of your database. This means the search will <strong>not</strong> be accurate. By switching to a different database system you will gain better searching! For more information, read the <a href="http://docs.djangoproject.com/en/dev/ref/databases/#sqlite-string-matching">Django Documentation on string matching in SQLite</a>.')
|
search_message = _('<p><strong>Note:</strong> Your keyword search is case sensitive because of your database. This means the search will <strong>not</strong> be accurate. By switching to a different database system you will gain better searching! For more information, read the <a href="http://docs.djangoproject.com/en/dev/ref/databases/#sqlite-string-matching">Django Documentation on string matching in SQLite</a>.')
|
||||||
@ -848,15 +841,12 @@ def ticket_list(request):
|
|||||||
|
|
||||||
user_saved_queries = SavedSearch.objects.filter(Q(user=request.user) | Q(shared__exact=True))
|
user_saved_queries = SavedSearch.objects.filter(Q(user=request.user) | Q(shared__exact=True))
|
||||||
|
|
||||||
querydict = request.GET.copy()
|
|
||||||
querydict.pop('page', 1)
|
|
||||||
|
|
||||||
|
|
||||||
return render(request, 'helpdesk/ticket_list.html',
|
return render(request, 'helpdesk/ticket_list.html',
|
||||||
dict(
|
dict(
|
||||||
context,
|
context,
|
||||||
query_string=querydict.urlencode(),
|
tickets=ticket_qs,
|
||||||
tickets=tickets,
|
default_tickets_per_page=request.user.usersettings.settings.get('tickets_per_page') or 25,
|
||||||
user_choices=User.objects.filter(is_active=True,is_staff=True),
|
user_choices=User.objects.filter(is_active=True,is_staff=True),
|
||||||
queue_choices=user_queues,
|
queue_choices=user_queues,
|
||||||
status_choices=Ticket.STATUS_CHOICES,
|
status_choices=Ticket.STATUS_CHOICES,
|
||||||
@ -1339,11 +1329,13 @@ def ticket_cc_add(request, ticket_id):
|
|||||||
ticketcc.save()
|
ticketcc.save()
|
||||||
return HttpResponseRedirect(reverse('helpdesk_ticket_cc', kwargs={'ticket_id': ticket.id}))
|
return HttpResponseRedirect(reverse('helpdesk_ticket_cc', kwargs={'ticket_id': ticket.id}))
|
||||||
else:
|
else:
|
||||||
form = TicketCCForm()
|
form_email = TicketCCEmailForm()
|
||||||
|
form_user = TicketCCUserForm()
|
||||||
return render(request, template_name='helpdesk/ticket_cc_add.html',
|
return render(request, template_name='helpdesk/ticket_cc_add.html',
|
||||||
context = {
|
context = {
|
||||||
'ticket': ticket,
|
'ticket': ticket,
|
||||||
'form': form,
|
'form_email': form_email,
|
||||||
|
'form_user': form_user,
|
||||||
})
|
})
|
||||||
ticket_cc_add = staff_member_required(ticket_cc_add)
|
ticket_cc_add = staff_member_required(ticket_cc_add)
|
||||||
|
|
||||||
@ -1395,9 +1387,16 @@ def attachment_del(request, ticket_id, attachment_id):
|
|||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|
||||||
attachment = get_object_or_404(Attachment, id=attachment_id)
|
attachment = get_object_or_404(Attachment, id=attachment_id)
|
||||||
|
if request.method == 'POST':
|
||||||
attachment.delete()
|
attachment.delete()
|
||||||
return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket_id]))
|
return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket_id]))
|
||||||
|
return render(request, template_name='helpdesk/ticket_attachment_del.html',
|
||||||
|
context = {
|
||||||
|
'attachment': attachment,
|
||||||
|
'filename': attachment.filename,
|
||||||
|
})
|
||||||
attachment_del = staff_member_required(attachment_del)
|
attachment_del = staff_member_required(attachment_del)
|
||||||
|
|
||||||
def calc_average_nbr_days_until_ticket_resolved(Tickets):
|
def calc_average_nbr_days_until_ticket_resolved(Tickets):
|
||||||
@ -1443,9 +1442,9 @@ def calc_basic_ticket_stats(Tickets):
|
|||||||
# (O)pen (T)icket (S)tats
|
# (O)pen (T)icket (S)tats
|
||||||
ots = list()
|
ots = list()
|
||||||
# label, number entries, color, sort_string
|
# label, number entries, color, sort_string
|
||||||
ots.append(['< 30 days', N_ota_le_30, get_color_for_nbr_days(N_ota_le_30), sort_string(date_30_str, ''), ])
|
ots.append(['Tickets < 30 days', N_ota_le_30, 'success', sort_string(date_30_str, ''), ])
|
||||||
ots.append(['30 - 60 days', N_ota_le_60_ge_30, get_color_for_nbr_days(N_ota_le_60_ge_30), sort_string(date_60_str, date_30_str), ])
|
ots.append(['Tickets 30 - 60 days', N_ota_le_60_ge_30, 'success' if N_ota_le_60_ge_30 == 0 else 'warning', sort_string(date_60_str, date_30_str), ])
|
||||||
ots.append(['> 60 days', N_ota_ge_60, get_color_for_nbr_days(N_ota_ge_60), sort_string('', date_60_str), ])
|
ots.append(['Tickets > 60 days', N_ota_ge_60, 'success' if N_ota_ge_60 == 0 else 'danger', sort_string('', date_60_str), ])
|
||||||
|
|
||||||
# all closed tickets - independent of user.
|
# all closed tickets - independent of user.
|
||||||
all_closed_tickets = Tickets.filter(status = Ticket.CLOSED_STATUS)
|
all_closed_tickets = Tickets.filter(status = Ticket.CLOSED_STATUS)
|
||||||
@ -1461,17 +1460,6 @@ def calc_basic_ticket_stats(Tickets):
|
|||||||
|
|
||||||
return basic_ticket_stats
|
return basic_ticket_stats
|
||||||
|
|
||||||
def get_color_for_nbr_days(nbr_days):
|
|
||||||
''' '''
|
|
||||||
if nbr_days < 5:
|
|
||||||
color_string = 'green'
|
|
||||||
elif nbr_days >= 5 and nbr_days < 10:
|
|
||||||
color_string = 'orange'
|
|
||||||
else: # more than 10 days
|
|
||||||
color_string = 'red'
|
|
||||||
|
|
||||||
return color_string
|
|
||||||
|
|
||||||
def days_since_created(today, ticket):
|
def days_since_created(today, ticket):
|
||||||
return (today - ticket.created).days
|
return (today - ticket.created).days
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user