forked from extern/django-helpdesk
Redo KB categories as accordion view
This commit is contained in:
parent
c95b24780e
commit
7fe6444f8f
@ -18,7 +18,7 @@ from django.utils import timezone
|
|||||||
|
|
||||||
from helpdesk.lib import safe_template_context, process_attachments
|
from helpdesk.lib import safe_template_context, process_attachments
|
||||||
from helpdesk.models import (Ticket, Queue, FollowUp, IgnoreEmail, TicketCC,
|
from helpdesk.models import (Ticket, Queue, FollowUp, IgnoreEmail, TicketCC,
|
||||||
CustomField, TicketCustomFieldValue, TicketDependency, UserSettings)
|
CustomField, TicketCustomFieldValue, TicketDependency, UserSettings, KBItem)
|
||||||
from helpdesk import settings as helpdesk_settings
|
from helpdesk import settings as helpdesk_settings
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
@ -197,7 +197,10 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
|
|||||||
return Queue.objects.get(id=int(self.cleaned_data['queue']))
|
return Queue.objects.get(id=int(self.cleaned_data['queue']))
|
||||||
|
|
||||||
def _create_ticket(self):
|
def _create_ticket(self):
|
||||||
queue = self._get_queue()
|
queue = Queue.objects.get(id=int(self.cleaned_data['queue']))
|
||||||
|
kbitem = None
|
||||||
|
if 'kbitem' in self.cleaned_data:
|
||||||
|
kbitem = KBItem.objects.get(id=int(self.cleaned_data['kbitem']))
|
||||||
|
|
||||||
ticket = Ticket(title=self.cleaned_data['title'],
|
ticket = Ticket(title=self.cleaned_data['title'],
|
||||||
submitter_email=self.cleaned_data['submitter_email'],
|
submitter_email=self.cleaned_data['submitter_email'],
|
||||||
@ -207,6 +210,7 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
|
|||||||
description=self.cleaned_data['body'],
|
description=self.cleaned_data['body'],
|
||||||
priority=self.cleaned_data['priority'],
|
priority=self.cleaned_data['priority'],
|
||||||
due_date=self.cleaned_data['due_date'],
|
due_date=self.cleaned_data['due_date'],
|
||||||
|
kbitem=kbitem,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ticket, queue
|
return ticket, queue
|
||||||
@ -337,13 +341,22 @@ class PublicTicketForm(AbstractTicketForm):
|
|||||||
help_text=_('We will e-mail you when your ticket is updated.'),
|
help_text=_('We will e-mail you when your ticket is updated.'),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, hidden_fields=(), readonly_fields=(), *args, **kwargs):
|
def __init__(self, hidden_fields=(), readonly_fields=(), kbcategory=None, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Add any (non-staff) custom fields that are defined to the form
|
Add any (non-staff) custom fields that are defined to the form
|
||||||
"""
|
"""
|
||||||
super(PublicTicketForm, self).__init__(*args, **kwargs)
|
super(PublicTicketForm, self).__init__(*args, **kwargs)
|
||||||
self._add_form_custom_fields(False)
|
self._add_form_custom_fields(False)
|
||||||
|
|
||||||
|
if kbcategory:
|
||||||
|
self.fields['kbitem'] = forms.ChoiceField(
|
||||||
|
widget=forms.Select(attrs={'class': 'form-control'}),
|
||||||
|
required=False,
|
||||||
|
label=_('Knowedge Base Item'),
|
||||||
|
choices=[(kbi.pk, kbi.title) for kbi in KBItem.objects.filter(category=kbcategory.pk)],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
field_hide_table = {
|
field_hide_table = {
|
||||||
'queue': 'HELPDESK_PUBLIC_TICKET_QUEUE',
|
'queue': 'HELPDESK_PUBLIC_TICKET_QUEUE',
|
||||||
'priority': 'HELPDESK_PUBLIC_TICKET_PRIORITY',
|
'priority': 'HELPDESK_PUBLIC_TICKET_PRIORITY',
|
||||||
|
@ -559,6 +559,14 @@ class Ticket(models.Model):
|
|||||||
default=mk_secret,
|
default=mk_secret,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
kbitem = models.ForeignKey(
|
||||||
|
"KBItem",
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name=_('Knowledge base item the user was viewing when they created this ticket.'),
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def time_spent(self):
|
def time_spent(self):
|
||||||
"""Return back total time spent on the ticket. This is calculated value
|
"""Return back total time spent on the ticket. This is calculated value
|
||||||
@ -1310,7 +1318,7 @@ class KBItem(models.Model):
|
|||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
return reverse('helpdesk:kb_item', args=(self.id,))
|
return str(reverse('helpdesk:kb_category', args=(self.category.slug,)))+"?kbitem="+str(self.pk)
|
||||||
|
|
||||||
def get_markdown(self):
|
def get_markdown(self):
|
||||||
return get_markdown(self.answer)
|
return get_markdown(self.answer)
|
||||||
|
@ -19,29 +19,37 @@
|
|||||||
<p>{{ category.description }}</p>
|
<p>{{ category.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="accordion">
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
{% cycle 'one' 'two' 'three' as itemnumperrow silent %}
|
<div class="card mb-3">
|
||||||
{% ifequal itemnumperrow 'one' %}<div class="card-deck">{% endifequal %}
|
<button class="btn btn-link" data-toggle="collapse" data-target="#collapse{{item.id}}" aria-expanded="true" aria-controls="collapse{{item.id}}">
|
||||||
<div class="card">
|
<div class="card-header" id="header{{item.id}}">
|
||||||
<div class="card-header">
|
<h5 class="mb-0">
|
||||||
<h5 class="card-title">{{ item.title }}</h5>
|
{{ item.title }}
|
||||||
</div>
|
</h5>
|
||||||
<div class="card-body">
|
</div>
|
||||||
<p class="card-text">{{ item.question }}</p>
|
</button>
|
||||||
<p class="card-text">
|
<div id="collapse{{item.id}}" class="collapse {% if item.id == selected_item %}show{% endif %}" aria-labelledby="header{{item.id}}" data-parent="#accordion">
|
||||||
{% blocktrans with item.get_absolute_url as url %}<a href='{{ url }}' class="btn btn-primary"> Go to answer <i class="fa fa-share"></i></a>{% endblocktrans %}
|
<div class="card-body">
|
||||||
</p>
|
<p class="card-text">{{ item.question }}</p>
|
||||||
<div class="well well-sm">
|
<p>{{ item.get_markdown }}</p>
|
||||||
<p>{% trans 'Rating' %}: {{ item.score }}</p>
|
<div class="row">
|
||||||
<p>{% trans 'Last Update' %}: {{ item.last_updated|naturaltime }}</p>
|
{% if request.user.pk %}
|
||||||
|
<div>
|
||||||
|
<a href='{% url "helpdesk:kb_vote" item.pk %}?vote=up'><button type="button" class="btn btn-success btn-circle btn-xl"><i class="fa fa-thumbs-up fa-lg"></i></button></a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href='{% url "helpdesk:kb_vote" item.pk %}?vote=down'><button type="button" class="btn btn-danger btn-circle btn-xl"><i class="fa fa-thumbs-down fa-lg"></i></button></a>
|
||||||
|
</div>
|
||||||
|
{% blocktrans with recommendations=item.recommendations votes=item.votes %}{{ recommendations }} people found this answer useful of {{votes}}. {% endblocktrans %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</p>
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% ifequal itemnumperrow 'three' %}</div>{% endifequal %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% ifnotequal itemnumperrow 'three' %}</div>{% endifnotequal %}
|
</div>
|
||||||
{% if category.queue %}
|
{% if category.queue %}
|
||||||
<a href='{% url 'helpdesk:submit' %}?queue={{category.queue.pk}};_readonly_fields_=queue'><button type="button" class="btn btn-success btn-circle btn-xl float-right"><i class="fa fa-envelope fa-lg"></i> {% trans 'Get help with this topic' %}</button></a>
|
<a href='{% url 'helpdesk:submit' %}?queue={{category.queue.pk}};_readonly_fields_=queue'><button type="button" class="btn btn-success btn-circle btn-xl float-right"><i class="fa fa-envelope fa-lg"></i> {% trans 'Get help with this topic' %}</button></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
{% extends "helpdesk/public_base.html" %}{% load i18n %}
|
|
||||||
|
|
||||||
{% block helpdesk_breadcrumb %}
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{% url 'helpdesk:kb_index' %}">{% trans "Knowledgebase" %}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ category.get_absolute_url }}">{% blocktrans with category.title as kbcat %}{{ kbcat }}{% endblocktrans %}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active">Overview</li>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block helpdesk_body %}
|
|
||||||
<h2>{% trans 'Knowledgebase' %}: {% blocktrans with item.title as item %}{{ item }}{% endblocktrans %}</h2>
|
|
||||||
|
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-header">
|
|
||||||
<i class="fas fa-question-circle"></i>
|
|
||||||
{{ item.question }}
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<p>{{ item.get_markdown }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-2">
|
|
||||||
<p>{% trans "Did you find this article useful?" %}</p>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<a href='vote/?vote=up'><button type="button" class="btn btn-success btn-circle btn-xl"><i class="fa fa-thumbs-up fa-lg"></i></button></a>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<a href='vote/?vote=down'><button type="button" class="btn btn-danger btn-circle btn-xl"><i class="fa fa-thumbs-down fa-lg"></i></button></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-10">
|
|
||||||
<p>{% trans "The results of voting by other readers of this article are below:" %}</p>
|
|
||||||
<ul>
|
|
||||||
<li>{% blocktrans with item.recommendations as recommendations %}Recommendations: {{ recommendations }}{% endblocktrans %}</li>
|
|
||||||
<li>{% blocktrans with item.votes as votes %}Votes: {{ votes }}{% endblocktrans %}</li>
|
|
||||||
<li>{% blocktrans with item.score as score %}Overall Rating: {{ score }}{% endblocktrans %}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>{% blocktrans with item.category.title as category_title and item.category.get_absolute_url as category_url %}View <a href='{{ category_url }}'>other <em>{{ category_title }}</em> articles</a>, or continue <a href='../'>viewing other knowledgebase articles</a>.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -232,10 +232,6 @@ if helpdesk_settings.HELPDESK_KB_ENABLED:
|
|||||||
kb.index,
|
kb.index,
|
||||||
name='kb_index'),
|
name='kb_index'),
|
||||||
|
|
||||||
url(r'^kb/(?P<item>[0-9]+)/$',
|
|
||||||
kb.item,
|
|
||||||
name='kb_item'),
|
|
||||||
|
|
||||||
url(r'^kb/(?P<item>[0-9]+)/vote/$',
|
url(r'^kb/(?P<item>[0-9]+)/vote/$',
|
||||||
kb.vote,
|
kb.vote,
|
||||||
name='kb_vote'),
|
name='kb_vote'),
|
||||||
|
@ -27,18 +27,15 @@ def index(request):
|
|||||||
def category(request, slug):
|
def category(request, slug):
|
||||||
category = get_object_or_404(KBCategory, slug__iexact=slug)
|
category = get_object_or_404(KBCategory, slug__iexact=slug)
|
||||||
items = category.kbitem_set.all()
|
items = category.kbitem_set.all()
|
||||||
|
selected_item = request.GET.get('kbitem', None)
|
||||||
|
try:
|
||||||
|
selected_item = int(selected_item)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
return render(request, 'helpdesk/kb_category.html', {
|
return render(request, 'helpdesk/kb_category.html', {
|
||||||
'category': category,
|
'category': category,
|
||||||
'items': items,
|
'items': items,
|
||||||
'helpdesk_settings': helpdesk_settings,
|
'selected_item': selected_item,
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
def item(request, item):
|
|
||||||
item = get_object_or_404(KBItem, pk=item)
|
|
||||||
return render(request, 'helpdesk/kb_item.html', {
|
|
||||||
'category': item.category,
|
|
||||||
'item': item,
|
|
||||||
'helpdesk_settings': helpdesk_settings,
|
'helpdesk_settings': helpdesk_settings,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from helpdesk.decorators import protect_view, is_helpdesk_staff
|
|||||||
import helpdesk.views.staff as staff
|
import helpdesk.views.staff as staff
|
||||||
from helpdesk.forms import PublicTicketForm
|
from helpdesk.forms import PublicTicketForm
|
||||||
from helpdesk.lib import text_is_spam
|
from helpdesk.lib import text_is_spam
|
||||||
from helpdesk.models import CustomField, Ticket, Queue, UserSettings, KBCategory
|
from helpdesk.models import CustomField, Ticket, Queue, UserSettings, KBCategory, KBItem
|
||||||
|
|
||||||
|
|
||||||
def create_ticket(request, *args, **kwargs):
|
def create_ticket(request, *args, **kwargs):
|
||||||
@ -82,7 +82,7 @@ class BaseCreateTicketView(FormView):
|
|||||||
if request.user.is_authenticated and request.user.email:
|
if request.user.is_authenticated and request.user.email:
|
||||||
initial_data['submitter_email'] = request.user.email
|
initial_data['submitter_email'] = request.user.email
|
||||||
|
|
||||||
query_param_fields = ['submitter_email', 'title', 'body', 'queue']
|
query_param_fields = ['submitter_email', 'title', 'body', 'queue', 'kbitem']
|
||||||
custom_fields = ["custom_%s" % f.name for f in CustomField.objects.filter(staff_only=False)]
|
custom_fields = ["custom_%s" % f.name for f in CustomField.objects.filter(staff_only=False)]
|
||||||
query_param_fields += custom_fields
|
query_param_fields += custom_fields
|
||||||
for qpf in query_param_fields:
|
for qpf in query_param_fields:
|
||||||
@ -93,6 +93,12 @@ class BaseCreateTicketView(FormView):
|
|||||||
kwargs = super().get_form_kwargs(*args, **kwargs)
|
kwargs = super().get_form_kwargs(*args, **kwargs)
|
||||||
kwargs['hidden_fields'] = self.request.GET.get('_hide_fields_', '').split(',')
|
kwargs['hidden_fields'] = self.request.GET.get('_hide_fields_', '').split(',')
|
||||||
kwargs['readonly_fields'] = self.request.GET.get('_readonly_fields_', '').split(',')
|
kwargs['readonly_fields'] = self.request.GET.get('_readonly_fields_', '').split(',')
|
||||||
|
kbitem = self.request.GET.get('kbitem', None)
|
||||||
|
if kbitem:
|
||||||
|
try:
|
||||||
|
kwargs['kbcategory'] = KBItem.objects.get(pk=int(kbitem))
|
||||||
|
except (ValueError, KBItem.DoesNotExist):
|
||||||
|
pass
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
Loading…
Reference in New Issue
Block a user