CRUD Checklist Template

This commit is contained in:
Benbb96 2023-04-30 01:05:46 +02:00
parent af1ba5f205
commit 308f69a03b
No known key found for this signature in database
10 changed files with 250 additions and 3 deletions

View File

@ -606,6 +606,22 @@ class MultipleTicketSelectForm(forms.Form):
return tickets return tickets
class ChecklistTemplateForm(forms.ModelForm):
name = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control'}),
required=True,
)
task_list = forms.JSONField(widget=forms.HiddenInput())
class Meta:
model = ChecklistTemplate
fields = ('name', 'task_list')
def clean_task_list(self):
task_list = self.cleaned_data['task_list']
return list(map(lambda task: task.strip(), task_list))
class ChecklistForm(forms.ModelForm): class ChecklistForm(forms.ModelForm):
name = forms.CharField( name = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control'}), widget=forms.TextInput(attrs={'class': 'form-control'}),

View File

@ -2010,7 +2010,7 @@ def is_a_list_without_empty_element(task_list):
for task in task_list: for task in task_list:
if not isinstance(task, str): if not isinstance(task, str):
raise ValidationError(f'{task} is not a string') raise ValidationError(f'{task} is not a string')
if task == '': if task.strip() == '':
raise ValidationError('A task cannot be an empty string') raise ValidationError('A task cannot be an empty string')

View File

@ -102,3 +102,7 @@ table .tickettitle {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.handle {
cursor: grab;
}

View File

@ -0,0 +1,47 @@
{% extends "helpdesk/base.html" %}
{% load i18n %}
{% block helpdesk_title %}{% trans "Delete Checklist Template" %}{% endblock %}
{% block helpdesk_breadcrumb %}
<li class="breadcrumb-item">
<a href="{% url 'helpdesk:system_settings' %}">{% trans "System Settings" %}</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'helpdesk:checklist_templates' %}">{% trans "Checklist Templates" %}</a>
</li>
<li class="breadcrumb-item active">
{{ checklist_template }}
</li>
{% endblock %}
{% block helpdesk_body %}
<div class="row">
<div class="col-sm-6 offset-sm-3 col-xs-12">
<div class="card">
<div class="card-header">
<h2>
{% trans "Delete Checklist Template" %}
</h2>
</div>
<div class="card-body">
<form method='post'>
{% csrf_token %}
<p>{% trans "Are you sure your want to delete checklist template" %} {{ checklist_template.name }} ?</p>
<div class='buttons form-group text-center'>
<a class="btn btn-secondary" href='{% url 'helpdesk:checklist_templates' %}'>
<i class="fas fa-times"></i>
{% trans "Don't Delete" %}
</a>
<button type='submit' class="btn btn-danger">
<i class="fas fa-trash"></i>
{% trans "Yes, I Understand - Delete" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,119 @@
{% extends "helpdesk/base.html" %}
{% load i18n %}
{% block helpdesk_title %}{% trans "Checklist Templates" %}{% endblock %}
{% block helpdesk_breadcrumb %}
<li class="breadcrumb-item">
<a href="{% url 'helpdesk:system_settings' %}">{% trans "System Settings" %}</a>
</li>
<li class="breadcrumb-item active">{% trans "Checklist Templates" %}</li>
{% endblock %}
{% block helpdesk_body %}
<h2>{% trans "Maintain checklist templates" %}</h2>
<div class="row mt-4">
<div class="col-sm-6 col-xs-12">
<div class="card">
<div class="card-header">
{% if checklist_template %}
{% trans "Edit checklist template" %}
{% else %}
{% trans "Create new checklist template" %}
{% endif %}
</div>
<form method="post">
<div class="card-body">
{% csrf_token %}
{{ form.as_p }}
<table class="table">
<thead>
<tr>
<th></th>
<th>Task</th>
<th class="text-center">Actions</th>
</tr>
</thead>
<tbody id="tasks">
{% if checklist_template %}
{% for value in checklist_template.task_list %}
{% include 'helpdesk/include/task_form_row.html' %}
{% endfor %}
{% else %}
{% include 'helpdesk/include/task_form_row.html' %}
{% endif %}
</tbody>
</table>
<button type="button" id="addTask" class="btn btn-sm btn-secondary">
<i class="fas fa-plus"></i>
{% trans "Add another task" %}
</button>
</div>
<div class="card-footer text-center">
{% if checklist_template %}
<a href="{% url 'helpdesk:checklist_templates' %}" class="btn btn-secondary">
<i class="fas fa-times"></i>
{% trans "Cancel" %}
</a>
{% endif %}
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
{% trans "Save checklist template" %}
</button>
</div>
</form>
</div>
</div>
<div class="col-sm-6 col-xs-12">
<div class="list-group">
{% for checklist in checklists %}
<div class="list-group-item d-flex justify-content-between align-items-center{% if checklist_template.id == checklist.id %} active{% endif %}">
<span>
{{ checklist.name }}
{% if checklist_template.id != checklist.id %}
<a class="btn btn-secondary btn-sm" href="{% url 'helpdesk:edit_checklist_template' checklist.id %}">
<i class="fas fa-edit"></i>
</a>
{% endif %}
<a class="btn btn-sm btn-danger" href="{% url 'helpdesk:delete_checklist_template' checklist.id %}">
<i class="fas fa-trash"></i>
</a>
</span>
<span class="badge badge-secondary badge-pill">{{ checklist.task_list|length }} tasks</span>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
{% block helpdesk_js %}
<script src="https://unpkg.com/sortablejs-make/Sortable.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-sortablejs@latest/jquery-sortable.js"></script>
<script>
const updateTemplateTaskList = () => {
let tasks = []
$('#tasks .taskInput').each((index, taskInput) => {
tasks.push($(taskInput).val())
})
$('#id_task_list').val(JSON.stringify(tasks))
}
const removeTask = (btn) => {
$(btn).parents('tr').remove()
updateTemplateTaskList()
}
$(() => {
$('#addTask').on('click', () => {
$('#tasks').append(`{% include 'helpdesk/include/task_form_row.html' %}`)
})
$('#tasks').sortable({
handle: '.handle',
onChange: updateTemplateTaskList
})
})
</script>
{% endblock %}

View File

@ -2,6 +2,13 @@
{% block helpdesk_title %}{% trans "Ignored E-Mail Addresses" %}{% endblock %} {% block helpdesk_title %}{% trans "Ignored E-Mail Addresses" %}{% endblock %}
{% block helpdesk_breadcrumb %}
<li class="breadcrumb-item">
<a href="{% url 'helpdesk:system_settings' %}">{% trans "System Settings" %}</a>
</li>
<li class="breadcrumb-item active">Ignored E-Mail Addresses</li>
{% endblock %}
{% block helpdesk_body %}{% blocktrans %} {% block helpdesk_body %}{% blocktrans %}
<h2>Ignored E-Mail Addresses</h2> <h2>Ignored E-Mail Addresses</h2>

View File

@ -0,0 +1,13 @@
<tr>
<td title="Drag & Drop" class="text-center handle">
<i class="fas fa-grip-vertical"></i>
</td>
<td>
<input class="form-control taskInput" oninput="updateTemplateTaskList()" required value="{{ value }}">
</td>
<td class="text-center">
<button type="button" class="btn btn-sm btn-danger" onclick="removeTask(this)">
<i class="fas fa-times"></i>
</button>
</td>
</tr>

View File

@ -18,6 +18,7 @@
<ul> <ul>
<li><a href='{% url 'helpdesk:email_ignore' %}'>{% trans "E-Mail Ignore list" %}</a></li> <li><a href='{% url 'helpdesk:email_ignore' %}'>{% trans "E-Mail Ignore list" %}</a></li>
<li><a href='{% url 'helpdesk:checklist_templates' %}'>{% trans "Checklist Templates" %}</a></li>
<li><a href='{% url 'admin:helpdesk_queue_changelist' %}'>{% trans "Maintain Queues" %}</a></li> <li><a href='{% url 'admin:helpdesk_queue_changelist' %}'>{% trans "Maintain Queues" %}</a></li>
<li><a href='{% url 'admin:helpdesk_presetreply_changelist' %}'>{% trans "Maintain Pre-Set Replies" %}</a></li> <li><a href='{% url 'admin:helpdesk_presetreply_changelist' %}'>{% trans "Maintain Pre-Set Replies" %}</a></li>
{% if helpdesk_settings.HELPDESK_KB_ENABLED %} {% if helpdesk_settings.HELPDESK_KB_ENABLED %}

View File

@ -115,6 +115,17 @@ urlpatterns = [
path("ignore/add/", staff.email_ignore_add, name="email_ignore_add"), path("ignore/add/", staff.email_ignore_add, name="email_ignore_add"),
path("ignore/delete/<int:id>/", path("ignore/delete/<int:id>/",
staff.email_ignore_del, name="email_ignore_del"), staff.email_ignore_del, name="email_ignore_del"),
path("checklist-templates/", staff.checklist_templates, name="checklist_templates"),
path(
"checklist-templates/<int:checklist_template_id>/",
staff.checklist_templates,
name="edit_checklist_template"
),
path(
"checklist-templates/<int:checklist_template_id>/delete/",
staff.delete_checklist_template,
name="delete_checklist_template"
),
re_path( re_path(
r"^datatables_ticket_list/(?P<query>{})$".format(base64_pattern), r"^datatables_ticket_list/(?P<query>{})$".format(base64_pattern),
staff.datatables_ticket_list, staff.datatables_ticket_list,

View File

@ -52,7 +52,8 @@ from helpdesk.forms import (
UserSettingsForm, UserSettingsForm,
CreateChecklistForm, CreateChecklistForm,
ChecklistForm, ChecklistForm,
FormControlDeleteFormSet FormControlDeleteFormSet,
ChecklistTemplateForm
) )
from helpdesk.lib import process_attachments, queue_template_context, safe_template_context from helpdesk.lib import process_attachments, queue_template_context, safe_template_context
from helpdesk.models import ( from helpdesk.models import (
@ -70,7 +71,8 @@ from helpdesk.models import (
TicketDependency, TicketDependency,
UserSettings, UserSettings,
Checklist, Checklist,
ChecklistTask ChecklistTask,
ChecklistTemplate
) )
from helpdesk.query import get_query_class, query_from_base64, query_to_base64 from helpdesk.query import get_query_class, query_from_base64, query_to_base64
from helpdesk.user import HelpdeskUser from helpdesk.user import HelpdeskUser
@ -2097,3 +2099,30 @@ def date_rel_to_today(today, offset):
def sort_string(begin, end): def sort_string(begin, end):
return 'sort=created&date_from=%s&date_to=%s&status=%s&status=%s&status=%s' % ( return 'sort=created&date_from=%s&date_to=%s&status=%s&status=%s&status=%s' % (
begin, end, Ticket.OPEN_STATUS, Ticket.REOPENED_STATUS, Ticket.RESOLVED_STATUS) begin, end, Ticket.OPEN_STATUS, Ticket.REOPENED_STATUS, Ticket.RESOLVED_STATUS)
@helpdesk_staff_member_required
def checklist_templates(request, checklist_template_id=None):
checklist_template = None
if checklist_template_id:
checklist_template = get_object_or_404(ChecklistTemplate, id=checklist_template_id)
form = ChecklistTemplateForm(request.POST or None, instance=checklist_template)
if form.is_valid():
form.save()
return redirect('helpdesk:checklist_templates')
return render(request, 'helpdesk/checklist_templates.html', {
'checklists': ChecklistTemplate.objects.all(),
'checklist_template': checklist_template,
'form': form
})
@helpdesk_staff_member_required
def delete_checklist_template(request, checklist_template_id):
checklist_template = get_object_or_404(ChecklistTemplate, id=checklist_template_id)
if request.POST:
checklist_template.delete()
return redirect('helpdesk:checklist_templates')
return render(request, 'helpdesk/checklist_template_confirm_delete.html', {
'checklist_template': checklist_template,
})