mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 05:22:16 +00:00
FEAT: Improve 'omni'search
- Partialised template - Added to assets header - Added ability to search assets/suppliers - Improved selection logic - Have it display current query
This commit is contained in:
@@ -23,6 +23,8 @@ urlpatterns = [
|
|||||||
path('api/<str:model>/<int:pk>/', login_required(views.SecureAPIRequest.as_view()),
|
path('api/<str:model>/<int:pk>/', login_required(views.SecureAPIRequest.as_view()),
|
||||||
name="api_secure"),
|
name="api_secure"),
|
||||||
|
|
||||||
|
path('search_help/', views.SearchHelp.as_view(), name='search_help'),
|
||||||
|
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -159,3 +159,7 @@ class GenericListView(generic.ListView):
|
|||||||
if orderBy != "":
|
if orderBy != "":
|
||||||
object_list = object_list.order_by(orderBy)
|
object_list = object_list.order_by(orderBy)
|
||||||
return object_list
|
return object_list
|
||||||
|
|
||||||
|
|
||||||
|
class SearchHelp(generic.TemplateView):
|
||||||
|
template_name = 'search_help.html'
|
||||||
|
|||||||
@@ -53,28 +53,11 @@
|
|||||||
{% if perms.RIGS.view_venue %}
|
{% if perms.RIGS.view_venue %}
|
||||||
<li class="nav-item"><a class="nav-link" href="{% url 'venue_list' %}">Venues</a></li>
|
<li class="nav-item"><a class="nav-link" href="{% url 'venue_list' %}">Venues</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form id="searchForm" class="form-inline flex-nowrap mx-3" role="form" method="GET">
|
|
||||||
<div class="input-group input-group-sm flex-nowrap">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<input id="id_search_input" type="search" name="q" class="form-control form-control-sm" placeholder="Search..." />
|
|
||||||
</div>
|
|
||||||
<select id="search-options" class="custom-select form-control">
|
|
||||||
<option selected data-action="{% url 'event_archive' %}" href="#">Events</option>
|
|
||||||
<option data-action="{% url 'person_list' %}" href="#">People</option>
|
|
||||||
<option data-action="{% url 'organisation_list' %}" href="#">Organisations</option>
|
|
||||||
<option data-action="{% url 'venue_list' %}" href="#">Venues</option>
|
|
||||||
{% if perms.RIGS.view_invoice %}
|
|
||||||
<option data-action="{% url 'invoice_archive' %}" href="#">Invoices</option>
|
|
||||||
{% endif %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-primary form-control form-control-sm btn-sm">Search</button>
|
|
||||||
<a href="{% url 'search_help' %}" class="nav-link modal-href btn-sm"><span class="fas fa-question-circle"></span></a>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block titleelements_right %}
|
{% block titleelements_right %}
|
||||||
|
{% include 'partials/search.html' %}
|
||||||
{% include 'partials/navbar_user.html' %}
|
{% include 'partials/navbar_user.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -86,17 +69,4 @@
|
|||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<script>
|
|
||||||
$(document).ready(function(){
|
|
||||||
$('#search-options option').click(function(){
|
|
||||||
$('#searchForm').attr('action', $(this).data('action')).submit();
|
|
||||||
});
|
|
||||||
$('#id_search_input').keypress(function (e) {
|
|
||||||
if (e.which == 13) {
|
|
||||||
$('#searchForm').attr('action', $('#search-options option').first().data('action')).submit();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ urlpatterns = [
|
|||||||
path('', login_required(views.Index.as_view()), name='index'),
|
path('', login_required(views.Index.as_view()), name='index'),
|
||||||
|
|
||||||
path('closemodal/', views.CloseModal.as_view(), name='closemodal'),
|
path('closemodal/', views.CloseModal.as_view(), name='closemodal'),
|
||||||
path('search_help/', views.SearchHelp.as_view(), name='search_help'),
|
|
||||||
|
|
||||||
# People
|
# People
|
||||||
path('people/', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
|
path('people/', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
|
||||||
|
|||||||
@@ -41,10 +41,6 @@ class Index(generic.TemplateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class SearchHelp(generic.TemplateView):
|
|
||||||
template_name = 'search_help.html'
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Called from a modal window (e.g. when an item is submitted to an event/invoice).
|
Called from a modal window (e.g. when an item is submitted to an event/invoice).
|
||||||
May optionally also include some javascript in a success message to cause a load of
|
May optionally also include some javascript in a success message to cause a load of
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class AssetAuditForm(AssetForm):
|
|||||||
|
|
||||||
|
|
||||||
class AssetSearchForm(forms.Form):
|
class AssetSearchForm(forms.Form):
|
||||||
query = forms.CharField(required=False)
|
q = forms.CharField(required=False)
|
||||||
category = forms.ModelMultipleChoiceField(models.AssetCategory.objects.all(), required=False)
|
category = forms.ModelMultipleChoiceField(models.AssetCategory.objects.all(), required=False)
|
||||||
status = forms.ModelMultipleChoiceField(models.AssetStatus.objects.all(), required=False)
|
status = forms.ModelMultipleChoiceField(models.AssetStatus.objects.all(), required=False)
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Asset List</h1>
|
<h1>Asset List</h1>
|
||||||
<form id="asset-search-form" method="GET" class="form py-2">
|
<form id="asset-search-form" method="GET" class="form">
|
||||||
<div class="row my-2">
|
<div class="row py-2">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
{% render_field form.query|add_class:'form-control' placeholder='Search by Asset ID/Desc/Serial' style="width: 250px"%}
|
{% render_field form.q|add_class:'form-control' placeholder='Search by Asset ID/Desc/Serial' style="width: 250px"%}
|
||||||
<label for="query" class="sr-only">Asset ID/Description/Serial Number:</label>
|
<label for="q" class="sr-only">Asset ID/Description/Serial Number:</label>
|
||||||
<span class="input-group-append"><button type="submit" class="btn btn-primary" id="id_search">Search</button></span>
|
<span class="input-group-append"><button type="submit" class="btn btn-primary" id="id_search">Search</button></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,5 +49,4 @@
|
|||||||
{% paginator %}
|
{% paginator %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -40,5 +40,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block titleelements_right %}
|
{% block titleelements_right %}
|
||||||
|
{% include 'partials/search.html' %}
|
||||||
{% include 'partials/navbar_user.html' %}
|
{% include 'partials/navbar_user.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class AssetList(LoginRequiredMixin, generic.ListView):
|
|||||||
return self.model.objects.none()
|
return self.model.objects.none()
|
||||||
|
|
||||||
# TODO Feedback to user when search fails
|
# TODO Feedback to user when search fails
|
||||||
query_string = form.cleaned_data['query'] or ""
|
query_string = form.cleaned_data['q'] or ""
|
||||||
if len(query_string) == 0:
|
if len(query_string) == 0:
|
||||||
queryset = self.model.objects.all()
|
queryset = self.model.objects.all()
|
||||||
elif len(query_string) >= 3:
|
elif len(query_string) >= 3:
|
||||||
|
|||||||
@@ -28,16 +28,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra-head %}{% endblock %}
|
{% block extra-head %}{% endblock %}
|
||||||
<script>
|
|
||||||
document.body.addEventListener('keydown', function(e) {
|
|
||||||
if(e.keyCode == 13 && (e.metaKey || e.ctrlKey)) {
|
|
||||||
var target = e.target;
|
|
||||||
if(target.form) {
|
|
||||||
target.form.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -132,6 +122,16 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script src="{% static 'js/dark-mode-switch.min.js' %}"></script>
|
<script src="{% static 'js/dark-mode-switch.min.js' %}"></script>
|
||||||
|
<script>
|
||||||
|
document.body.addEventListener('keydown', function(e) {
|
||||||
|
if(e.keyCode == 13 && (e.metaKey || e.ctrlKey)) {
|
||||||
|
var target = e.target;
|
||||||
|
if(target.form) {
|
||||||
|
target.form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
38
templates/partials/search.html
Normal file
38
templates/partials/search.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{% if user.is_authenticated %}
|
||||||
|
<form id="searchForm" class="form-inline flex-nowrap mx-3" role="form" method="GET">
|
||||||
|
<div class="input-group input-group-sm flex-nowrap">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<input id="id_search_input" type="search" name="q" class="form-control form-control-sm" placeholder="Search..." value="{{ request.GET.q }}" />
|
||||||
|
</div>
|
||||||
|
<select id="search-options" class="custom-select form-control">
|
||||||
|
<option selected data-action="{% url 'event_archive' %}" href="#">Events</option>
|
||||||
|
<option data-action="{% url 'person_list' %}" href="#">People</option>
|
||||||
|
<option data-action="{% url 'organisation_list' %}" href="#">Organisations</option>
|
||||||
|
<option data-action="{% url 'venue_list' %}" href="#">Venues</option>
|
||||||
|
{% if perms.RIGS.view_invoice %}
|
||||||
|
<option data-action="{% url 'invoice_archive' %}" href="#">Invoices</option>
|
||||||
|
{% endif %}
|
||||||
|
<option data-action="{% url 'asset_list' %}" href="#">Assets</option>
|
||||||
|
<option data-action="{% url 'supplier_list' %}" href="#">Suppliers</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary form-control form-control-sm btn-sm">Search</button>
|
||||||
|
<a href="{% url 'search_help' %}" class="nav-link modal-href btn-sm"><span class="fas fa-question-circle"></span></a>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<script>
|
||||||
|
$('#search-options').change(function(){
|
||||||
|
$('#searchForm').attr('action', $(this).children('option:selected').data('action'));
|
||||||
|
});
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('#id_search_input').keypress(function (e) {
|
||||||
|
if (e.which == 13) {
|
||||||
|
$('#searchForm').attr('action', $('#search-options option').first().data('action')).submit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<p>Events are sorted in reverse <span class="badge badge-dark">start_date</span> order (most recent events at the top)</p>
|
<p>Events are sorted in reverse <span class="badge badge-dark">start_date</span> order (most recent events at the top)</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">Searching People/Organisations/Venues</h3>
|
<h3 class="card-title">Searching People/Organisations/Venues/Suppliers</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>
|
<p>
|
||||||
@@ -54,7 +54,21 @@
|
|||||||
<p>Entering a raw integer will search by both <span class="badge badge-dark">invoice_id</span> and <span class="badge badge-dark">event_id</span></p>
|
<p>Entering a raw integer will search by both <span class="badge badge-dark">invoice_id</span> and <span class="badge badge-dark">event_id</span></p>
|
||||||
<p>Entries are sorted in reverse <span class="badge badge-dark">invoice_date</span> order</p>
|
<p>Entries are sorted in reverse <span class="badge badge-dark">invoice_date</span> order</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Searching Assets</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
Searches for entire search phrase in:
|
||||||
|
<span class="badge badge-dark">description</span> and
|
||||||
|
<span class="badge badge-dark">serial number</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Will also attempt to exact match <span class="badge badge-dark">asset ID</span>
|
||||||
|
</p>
|
||||||
|
<p>Entries are sorted in alphanumerical order by <span class="badge badge-dark">asset ID</span></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user