mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-30 12:36:45 +00:00
Merge pull request #2783 from SchrodingersGat/search-megamenu
Search megamenu
This commit is contained in:
commit
e5a7ee0afd
@ -1018,4 +1018,33 @@ input[type='number']{
|
|||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quicksearch Panel */
|
||||||
|
|
||||||
|
.search-result-panel {
|
||||||
|
max-width: 800px;
|
||||||
|
width: 75%
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-group {
|
||||||
|
padding: 5px;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-group-buttons > button{
|
||||||
|
padding: 2px;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-entry {
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
padding: 3px;
|
||||||
|
margin-top: 3px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
@ -128,81 +128,6 @@ function inventreeDocReady() {
|
|||||||
attachClipboard('.clip-btn', 'modal-about');
|
attachClipboard('.clip-btn', 'modal-about');
|
||||||
attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text');
|
attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text');
|
||||||
|
|
||||||
// Add autocomplete to the search-bar
|
|
||||||
if ($('#search-bar').exists()) {
|
|
||||||
$('#search-bar').autocomplete({
|
|
||||||
source: function(request, response) {
|
|
||||||
|
|
||||||
var params = {
|
|
||||||
search: request.term,
|
|
||||||
limit: user_settings.SEARCH_PREVIEW_RESULTS,
|
|
||||||
offset: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (user_settings.SEARCH_HIDE_INACTIVE_PARTS) {
|
|
||||||
// Limit to active parts
|
|
||||||
params.active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: '/api/part/',
|
|
||||||
data: params,
|
|
||||||
success: function(data) {
|
|
||||||
|
|
||||||
var transformed = $.map(data.results, function(el) {
|
|
||||||
return {
|
|
||||||
label: el.full_name,
|
|
||||||
id: el.pk,
|
|
||||||
thumbnail: el.thumbnail,
|
|
||||||
data: el,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
response(transformed);
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
response([]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
create: function() {
|
|
||||||
$(this).data('ui-autocomplete')._renderItem = function(ul, item) {
|
|
||||||
|
|
||||||
var html = `
|
|
||||||
<div class='search-autocomplete-item' title='${item.data.description}'>
|
|
||||||
<a href='/part/${item.id}/'>
|
|
||||||
<span style='padding-right: 10px;'><img class='hover-img-thumb' src='${item.thumbnail || "/static/img/blank_image.png"}'> ${item.label}</span>
|
|
||||||
</a>
|
|
||||||
<span class='flex' style='flex-grow: 1;'></span>
|
|
||||||
`;
|
|
||||||
|
|
||||||
if (user_settings.SEARCH_SHOW_STOCK_LEVELS) {
|
|
||||||
html += partStockLabel(
|
|
||||||
item.data,
|
|
||||||
{
|
|
||||||
classes: 'badge-right',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
return $('<li>').append(html).appendTo(ul);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
select: function( event, ui ) {
|
|
||||||
window.location = '/part/' + ui.item.id + '/';
|
|
||||||
},
|
|
||||||
minLength: 2,
|
|
||||||
classes: {
|
|
||||||
'ui-autocomplete': 'dropdown-menu search-menu',
|
|
||||||
},
|
|
||||||
position: {
|
|
||||||
my : "right top",
|
|
||||||
at: "right bottom"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate brand-icons
|
// Generate brand-icons
|
||||||
$('.brand-icon').each(function(i, obj) {
|
$('.brand-icon').each(function(i, obj) {
|
||||||
loadBrandIcon($(this), $(this).attr('brand_name'));
|
loadBrandIcon($(this), $(this).attr('brand_name'));
|
||||||
@ -231,8 +156,13 @@ function inventreeDocReady() {
|
|||||||
stopNotificationWatcher();
|
stopNotificationWatcher();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#offcanvasRight').on('show.bs.offcanvas', openNotificationPanel); // listener for opening the notification panel
|
// Calbacks for search panel
|
||||||
$('#offcanvasRight').on('hidden.bs.offcanvas', closeNotificationPanel); // listener for closing the notification panel
|
$('#offcanvas-search').on('shown.bs.offcanvas', openSearchPanel);
|
||||||
|
$('#offcanvas-search').on('hidden.bs.offcanvas', closeSearchPanel);
|
||||||
|
|
||||||
|
// Callbacks for notifications panel
|
||||||
|
$('#offcanvas-notification').on('show.bs.offcanvas', openNotificationPanel); // listener for opening the notification panel
|
||||||
|
$('#offcanvas-notification').on('hidden.bs.offcanvas', closeNotificationPanel); // listener for closing the notification panel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ class ViewTests(TestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Change this number as more javascript files are added to the index page
|
# Change this number as more javascript files are added to the index page
|
||||||
N_SCRIPT_FILES = 37
|
N_SCRIPT_FILES = 38
|
||||||
|
|
||||||
content = self.get_index_page()
|
content = self.get_index_page()
|
||||||
|
|
||||||
|
@ -130,6 +130,7 @@ translated_javascript_urls = [
|
|||||||
url(r'^order.js', DynamicJsView.as_view(template_name='js/translated/order.js'), name='order.js'),
|
url(r'^order.js', DynamicJsView.as_view(template_name='js/translated/order.js'), name='order.js'),
|
||||||
url(r'^part.js', DynamicJsView.as_view(template_name='js/translated/part.js'), name='part.js'),
|
url(r'^part.js', DynamicJsView.as_view(template_name='js/translated/part.js'), name='part.js'),
|
||||||
url(r'^report.js', DynamicJsView.as_view(template_name='js/translated/report.js'), name='report.js'),
|
url(r'^report.js', DynamicJsView.as_view(template_name='js/translated/report.js'), name='report.js'),
|
||||||
|
url(r'^search.js', DynamicJsView.as_view(template_name='js/translated/search.js'), name='search.js'),
|
||||||
url(r'^stock.js', DynamicJsView.as_view(template_name='js/translated/stock.js'), name='stock.js'),
|
url(r'^stock.js', DynamicJsView.as_view(template_name='js/translated/stock.js'), name='stock.js'),
|
||||||
url(r'^plugin.js', DynamicJsView.as_view(template_name='js/translated/plugin.js'), name='plugin.js'),
|
url(r'^plugin.js', DynamicJsView.as_view(template_name='js/translated/plugin.js'), name='plugin.js'),
|
||||||
url(r'^tables.js', DynamicJsView.as_view(template_name='js/translated/tables.js'), name='tables.js'),
|
url(r'^tables.js', DynamicJsView.as_view(template_name='js/translated/tables.js'), name='tables.js'),
|
||||||
|
@ -1268,20 +1268,62 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
'SEARCH_PREVIEW_RESULTS': {
|
'SEARCH_PREVIEW_SHOW_PARTS': {
|
||||||
'name': _('Search Preview Results'),
|
'name': _('Search Parts'),
|
||||||
'description': _('Number of results to show in search preview window'),
|
'description': _('Display parts in search preview window'),
|
||||||
'default': 10,
|
|
||||||
'validator': [int, MinValueValidator(1)]
|
|
||||||
},
|
|
||||||
|
|
||||||
'SEARCH_SHOW_STOCK_LEVELS': {
|
|
||||||
'name': _('Search Show Stock'),
|
|
||||||
'description': _('Display stock levels in search preview window'),
|
|
||||||
'default': True,
|
'default': True,
|
||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_CATEGORIES': {
|
||||||
|
'name': _('Search Categories'),
|
||||||
|
'description': _('Display part categories in search preview window'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_STOCK': {
|
||||||
|
'name': _('Search Stock'),
|
||||||
|
'description': _('Display stock items in search preview window'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_LOCATIONS': {
|
||||||
|
'name': _('Search Locations'),
|
||||||
|
'description': _('Display stock locations in search preview window'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_COMPANIES': {
|
||||||
|
'name': _('Search Companies'),
|
||||||
|
'description': _('Display companies in search preview window'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_PURCHASE_ORDERS': {
|
||||||
|
'name': _('Search Purchase Orders'),
|
||||||
|
'description': _('Display purchase orders in search preview window'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_SALES_ORDERS': {
|
||||||
|
'name': _('Search Sales Orders'),
|
||||||
|
'description': _('Display sales orders in search preview window'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_RESULTS': {
|
||||||
|
'name': _('Search Preview Results'),
|
||||||
|
'description': _('Number of results to show in each section of the search preview window'),
|
||||||
|
'default': 10,
|
||||||
|
'validator': [int, MinValueValidator(1)]
|
||||||
|
},
|
||||||
|
|
||||||
'SEARCH_HIDE_INACTIVE_PARTS': {
|
'SEARCH_HIDE_INACTIVE_PARTS': {
|
||||||
'name': _("Hide Inactive Parts"),
|
'name': _("Hide Inactive Parts"),
|
||||||
'description': _('Hide inactive parts in search preview window'),
|
'description': _('Hide inactive parts in search preview window'),
|
||||||
|
@ -14,8 +14,16 @@
|
|||||||
<div class='row'>
|
<div class='row'>
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_PARTS" user_setting=True icon='fa-shapes' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_CATEGORIES" user_setting=True icon='fa-sitemap' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_STOCK" user_setting=True icon='fa-boxes' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_LOCATIONS" user_setting=True icon='fa-sitemap' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_COMPANIES" user_setting=True icon='fa-building' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_PURCHASE_ORDERS" user_setting=True icon='fa-shopping-cart' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_SALES_ORDERS" user_setting=True icon='fa-truck' %}
|
||||||
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_RESULTS" user_setting=True icon='fa-search' %}
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_RESULTS" user_setting=True icon='fa-search' %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_SHOW_STOCK_LEVELS" user_setting=True icon='fa-boxes' %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_HIDE_INACTIVE_PARTS" user_setting=True icon='fa-eye-slash' %}
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_HIDE_INACTIVE_PARTS" user_setting=True icon='fa-eye-slash' %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -127,9 +127,11 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include 'modals.html' %}
|
{% include 'modals.html' %}
|
||||||
{% include 'about.html' %}
|
{% include 'about.html' %}
|
||||||
{% include "notifications.html" %}
|
{% include "notifications.html" %}
|
||||||
|
{% include "search.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
@ -186,6 +188,7 @@
|
|||||||
<script type='text/javascript' src="{% i18n_static 'order.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'order.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'part.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'part.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'report.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'report.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% i18n_static 'search.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'stock.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'stock.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'plugin.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'plugin.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'tables.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'tables.js' %}"></script>
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
renderCompany,
|
renderCompany,
|
||||||
renderManufacturerPart,
|
renderManufacturerPart,
|
||||||
renderOwner,
|
renderOwner,
|
||||||
|
renderPart,
|
||||||
renderPartCategory,
|
renderPartCategory,
|
||||||
|
renderStockItem,
|
||||||
renderStockLocation,
|
renderStockLocation,
|
||||||
renderSupplierPart,
|
renderSupplierPart,
|
||||||
*/
|
*/
|
||||||
@ -31,7 +33,7 @@
|
|||||||
|
|
||||||
// Renderer for "Company" model
|
// Renderer for "Company" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderCompany(name, data, parameters, options) {
|
function renderCompany(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var html = select2Thumbnail(data.image);
|
var html = select2Thumbnail(data.image);
|
||||||
|
|
||||||
@ -45,7 +47,7 @@ function renderCompany(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "StockItem" model
|
// Renderer for "StockItem" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderStockItem(name, data, parameters, options) {
|
function renderStockItem(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var image = blankImage();
|
var image = blankImage();
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ function renderStockItem(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "StockLocation" model
|
// Renderer for "StockLocation" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderStockLocation(name, data, parameters, options) {
|
function renderStockLocation(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var level = '- '.repeat(data.level);
|
var level = '- '.repeat(data.level);
|
||||||
|
|
||||||
@ -133,7 +135,7 @@ function renderStockLocation(name, data, parameters, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderBuild(name, data, parameters, options) {
|
function renderBuild(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var image = null;
|
var image = null;
|
||||||
|
|
||||||
@ -154,7 +156,7 @@ function renderBuild(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "Part" model
|
// Renderer for "Part" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderPart(name, data, parameters, options) {
|
function renderPart(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var html = select2Thumbnail(data.image);
|
var html = select2Thumbnail(data.image);
|
||||||
|
|
||||||
@ -164,13 +166,14 @@ function renderPart(name, data, parameters, options) {
|
|||||||
html += ` - <i><small>${data.description}</small></i>`;
|
html += ` - <i><small>${data.description}</small></i>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var extra = '';
|
var stock_data = '';
|
||||||
|
|
||||||
// Display available part quantity
|
|
||||||
if (user_settings.PART_SHOW_QUANTITY_IN_FORMS) {
|
if (user_settings.PART_SHOW_QUANTITY_IN_FORMS) {
|
||||||
extra += partStockLabel(data);
|
stock_data = partStockLabel(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var extra = '';
|
||||||
|
|
||||||
if (!data.active) {
|
if (!data.active) {
|
||||||
extra += `<span class='badge badge-right rounded-pill bg-danger'>{% trans "Inactive" %}</span>`;
|
extra += `<span class='badge badge-right rounded-pill bg-danger'>{% trans "Inactive" %}</span>`;
|
||||||
}
|
}
|
||||||
@ -178,6 +181,7 @@ function renderPart(name, data, parameters, options) {
|
|||||||
html += `
|
html += `
|
||||||
<span class='float-right'>
|
<span class='float-right'>
|
||||||
<small>
|
<small>
|
||||||
|
${stock_data}
|
||||||
${extra}
|
${extra}
|
||||||
{% trans "Part ID" %}: ${data.pk}
|
{% trans "Part ID" %}: ${data.pk}
|
||||||
</small>
|
</small>
|
||||||
@ -188,7 +192,7 @@ function renderPart(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "User" model
|
// Renderer for "User" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderUser(name, data, parameters, options) {
|
function renderUser(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var html = `<span>${data.username}</span>`;
|
var html = `<span>${data.username}</span>`;
|
||||||
|
|
||||||
@ -202,7 +206,7 @@ function renderUser(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "Owner" model
|
// Renderer for "Owner" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderOwner(name, data, parameters, options) {
|
function renderOwner(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var html = `<span>${data.name}</span>`;
|
var html = `<span>${data.name}</span>`;
|
||||||
|
|
||||||
@ -223,15 +227,13 @@ function renderOwner(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "PurchaseOrder" model
|
// Renderer for "PurchaseOrder" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderPurchaseOrder(name, data, parameters, options) {
|
function renderPurchaseOrder(name, data, parameters={}, options={}) {
|
||||||
var html = '';
|
|
||||||
|
|
||||||
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
||||||
|
var html = `<span>${prefix}${data.reference}</span>`;
|
||||||
|
|
||||||
var thumbnail = null;
|
var thumbnail = null;
|
||||||
|
|
||||||
html += `<span>${prefix}${data.reference}</span>`;
|
|
||||||
|
|
||||||
if (data.supplier_detail) {
|
if (data.supplier_detail) {
|
||||||
thumbnail = data.supplier_detail.thumbnail || data.supplier_detail.image;
|
thumbnail = data.supplier_detail.thumbnail || data.supplier_detail.image;
|
||||||
|
|
||||||
@ -257,8 +259,19 @@ function renderPurchaseOrder(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "SalesOrder" model
|
// Renderer for "SalesOrder" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderSalesOrder(name, data, parameters, options) {
|
function renderSalesOrder(name, data, parameters={}, options={}) {
|
||||||
var html = `<span>${data.reference}</span>`;
|
|
||||||
|
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
||||||
|
var html = `<span>${prefix}${data.reference}</span>`;
|
||||||
|
|
||||||
|
var thumbnail = null;
|
||||||
|
|
||||||
|
if (data.customer_detail) {
|
||||||
|
thumbnail = data.customer_detail.thumbnail || data.customer_detail.image;
|
||||||
|
|
||||||
|
html += ' - ' + select2Thumbnail(thumbnail);
|
||||||
|
html += `<span>${data.customer_detail.name}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.description) {
|
if (data.description) {
|
||||||
html += ` - <em>${data.description}</em>`;
|
html += ` - <em>${data.description}</em>`;
|
||||||
@ -277,7 +290,7 @@ function renderSalesOrder(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "SalesOrderShipment" model
|
// Renderer for "SalesOrderShipment" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderSalesOrderShipment(name, data, parameters, options) {
|
function renderSalesOrderShipment(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var so_prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
var so_prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
@ -294,7 +307,7 @@ function renderSalesOrderShipment(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "PartCategory" model
|
// Renderer for "PartCategory" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderPartCategory(name, data, parameters, options) {
|
function renderPartCategory(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var level = '- '.repeat(data.level);
|
var level = '- '.repeat(data.level);
|
||||||
|
|
||||||
@ -310,7 +323,7 @@ function renderPartCategory(name, data, parameters, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderPartParameterTemplate(name, data, parameters, options) {
|
function renderPartParameterTemplate(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var units = '';
|
var units = '';
|
||||||
|
|
||||||
@ -326,7 +339,7 @@ function renderPartParameterTemplate(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "ManufacturerPart" model
|
// Renderer for "ManufacturerPart" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderManufacturerPart(name, data, parameters, options) {
|
function renderManufacturerPart(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var manufacturer_image = null;
|
var manufacturer_image = null;
|
||||||
var part_image = null;
|
var part_image = null;
|
||||||
@ -355,7 +368,7 @@ function renderManufacturerPart(name, data, parameters, options) {
|
|||||||
|
|
||||||
// Renderer for "SupplierPart" model
|
// Renderer for "SupplierPart" model
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderSupplierPart(name, data, parameters, options) {
|
function renderSupplierPart(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var supplier_image = null;
|
var supplier_image = null;
|
||||||
var part_image = null;
|
var part_image = null;
|
||||||
|
325
InvenTree/templates/js/translated/search.js
Normal file
325
InvenTree/templates/js/translated/search.js
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
/* globals
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* exported
|
||||||
|
closeSearchPanel,
|
||||||
|
openSearchPanel,
|
||||||
|
searchTextChanged,
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback when the search panel is closed
|
||||||
|
*/
|
||||||
|
function closeSearchPanel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback when the search panel is opened.
|
||||||
|
* Ensure the panel is in a known state
|
||||||
|
*/
|
||||||
|
function openSearchPanel() {
|
||||||
|
|
||||||
|
var panel = $('#offcanvas-search');
|
||||||
|
|
||||||
|
clearSearchResults();
|
||||||
|
|
||||||
|
panel.find('#search-input').on('keyup change', searchTextChanged);
|
||||||
|
|
||||||
|
// Callback for "clear search" button
|
||||||
|
panel.find('#search-clear').click(function(event) {
|
||||||
|
|
||||||
|
// Prevent this button from actually submitting the form
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
panel.find('#search-input').val('');
|
||||||
|
clearSearchResults();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Callback for the "close search" button
|
||||||
|
panel.find('#search-close').click(function(event) {
|
||||||
|
// Prevent this button from actually submitting the form
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchInputTimer = null;
|
||||||
|
var searchText = null;
|
||||||
|
var searchTextCurrent = null;
|
||||||
|
var searchQueries = [];
|
||||||
|
|
||||||
|
function searchTextChanged(event) {
|
||||||
|
|
||||||
|
searchText = $('#offcanvas-search').find('#search-input').val();
|
||||||
|
|
||||||
|
clearTimeout(searchInputTimer);
|
||||||
|
searchInputTimer = setTimeout(updateSearch, 250);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function updateSearch() {
|
||||||
|
|
||||||
|
if (searchText == searchTextCurrent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSearchResults();
|
||||||
|
|
||||||
|
if (searchText.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchTextCurrent = searchText;
|
||||||
|
|
||||||
|
// Cancel any previous AJAX requests
|
||||||
|
searchQueries.forEach(function(query) {
|
||||||
|
query.abort();
|
||||||
|
});
|
||||||
|
|
||||||
|
searchQueries = [];
|
||||||
|
|
||||||
|
// Show the "searching" text
|
||||||
|
$('#offcanvas-search').find('#search-pending').show();
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_PARTS) {
|
||||||
|
|
||||||
|
var params = {};
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_HIDE_INACTIVE_PARTS) {
|
||||||
|
params.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for matching parts
|
||||||
|
addSearchQuery(
|
||||||
|
'part',
|
||||||
|
'{% trans "Parts" %}',
|
||||||
|
'{% url "api-part-list" %}',
|
||||||
|
params,
|
||||||
|
renderPart,
|
||||||
|
{
|
||||||
|
url: '/part',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_CATEGORIES) {
|
||||||
|
// Search for matching part categories
|
||||||
|
addSearchQuery(
|
||||||
|
'category',
|
||||||
|
'{% trans "Part Categories" %}',
|
||||||
|
'{% url "api-part-category-list" %}',
|
||||||
|
{},
|
||||||
|
renderPartCategory,
|
||||||
|
{
|
||||||
|
url: '/part/category',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_STOCK) {
|
||||||
|
// Search for matching stock items
|
||||||
|
addSearchQuery(
|
||||||
|
'stock',
|
||||||
|
'{% trans "Stock Items" %}',
|
||||||
|
'{% url "api-stock-list" %}',
|
||||||
|
{
|
||||||
|
part_detail: true,
|
||||||
|
location_detail: true,
|
||||||
|
},
|
||||||
|
renderStockItem,
|
||||||
|
{
|
||||||
|
url: '/stock/item',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_LOCATIONS) {
|
||||||
|
// Search for matching stock locations
|
||||||
|
addSearchQuery(
|
||||||
|
'location',
|
||||||
|
'{% trans "Stock Locations" %}',
|
||||||
|
'{% url "api-location-list" %}',
|
||||||
|
{},
|
||||||
|
renderStockLocation,
|
||||||
|
{
|
||||||
|
url: '/stock/location',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_COMPANIES) {
|
||||||
|
// Search for matching companies
|
||||||
|
addSearchQuery(
|
||||||
|
'company',
|
||||||
|
'{% trans "Companies" %}',
|
||||||
|
'{% url "api-company-list" %}',
|
||||||
|
{},
|
||||||
|
renderCompany,
|
||||||
|
{
|
||||||
|
url: '/company',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_PURCHASE_ORDERS) {
|
||||||
|
// Search for matching purchase orders
|
||||||
|
addSearchQuery(
|
||||||
|
'purchaseorder',
|
||||||
|
'{% trans "Purchase Orders" %}',
|
||||||
|
'{% url "api-po-list" %}',
|
||||||
|
{
|
||||||
|
supplier_detail: true,
|
||||||
|
outstanding: true,
|
||||||
|
},
|
||||||
|
renderPurchaseOrder,
|
||||||
|
{
|
||||||
|
url: '/order/purchase-order',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_SALES_ORDERS) {
|
||||||
|
// Search for matching sales orders
|
||||||
|
addSearchQuery(
|
||||||
|
'salesorder',
|
||||||
|
'{% trans "Sales Orders" %}',
|
||||||
|
'{% url "api-so-list" %}',
|
||||||
|
{
|
||||||
|
customer_detail: true,
|
||||||
|
outstanding: true,
|
||||||
|
},
|
||||||
|
renderSalesOrder,
|
||||||
|
{
|
||||||
|
url: '/order/sales-order',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until all the pending queries are completed
|
||||||
|
$.when.apply($, searchQueries).done(function() {
|
||||||
|
$('#offcanvas-search').find('#search-pending').hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function clearSearchResults() {
|
||||||
|
|
||||||
|
var panel = $('#offcanvas-search');
|
||||||
|
|
||||||
|
// Ensure the 'no results found' element is visible
|
||||||
|
panel.find('#search-no-results').show();
|
||||||
|
|
||||||
|
// Ensure that the 'searching' element is hidden
|
||||||
|
panel.find('#search-pending').hide();
|
||||||
|
|
||||||
|
// Delete any existing search results
|
||||||
|
panel.find('#search-results').empty();
|
||||||
|
|
||||||
|
// Finally, grab keyboard focus in the search bar
|
||||||
|
panel.find('#search-input').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addSearchQuery(key, title, query_url, query_params, render_func, render_params={}) {
|
||||||
|
|
||||||
|
// Include current search term
|
||||||
|
query_params.search = searchTextCurrent;
|
||||||
|
|
||||||
|
// How many results to show in each group?
|
||||||
|
query_params.offset = 0;
|
||||||
|
query_params.limit = user_settings.SEARCH_PREVIEW_RESULTS;
|
||||||
|
|
||||||
|
// Add the result group to the panel
|
||||||
|
$('#offcanvas-search').find('#search-results').append(`
|
||||||
|
<div class='search-result-group-wrapper' id='search-results-wrapper-${key}'></div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
var request = inventreeGet(
|
||||||
|
query_url,
|
||||||
|
query_params,
|
||||||
|
{
|
||||||
|
success: function(response) {
|
||||||
|
addSearchResults(
|
||||||
|
key,
|
||||||
|
response.results,
|
||||||
|
title,
|
||||||
|
render_func,
|
||||||
|
render_params,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add the query to the stack
|
||||||
|
searchQueries.push(request);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add a group of results to the list
|
||||||
|
function addSearchResults(key, results, title, renderFunc, renderParams={}) {
|
||||||
|
|
||||||
|
if (results.length == 0) {
|
||||||
|
// Do not display this group, as there are no results
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var panel = $('#offcanvas-search');
|
||||||
|
|
||||||
|
// Ensure the 'no results found' element is hidden
|
||||||
|
panel.find('#search-no-results').hide();
|
||||||
|
|
||||||
|
panel.find(`#search-results-wrapper-${key}`).append(`
|
||||||
|
<div class='search-result-group' id='search-results-${key}'>
|
||||||
|
<div class='search-result-header' style='display: flex;'>
|
||||||
|
<h5>${title}</h5>
|
||||||
|
<span class='flex' style='flex-grow: 1;'></span>
|
||||||
|
<div class='search-result-group-buttons btn-group float-right' role='group'>
|
||||||
|
<button class='btn btn-outline-secondary' id='hide-results-${key}' title='{% trans "Minimize results" %}'>
|
||||||
|
<span class='fas fa-chevron-up'></span>
|
||||||
|
</button>
|
||||||
|
<button class='btn btn-outline-secondary' id='remove-results-${key}' title='{% trans "Remove results" %}'>
|
||||||
|
<span class='fas fa-times icon-red'></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='collapse search-result-list' id='search-result-list-${key}'>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
results.forEach(function(result) {
|
||||||
|
|
||||||
|
var pk = result.pk || result.id;
|
||||||
|
|
||||||
|
var html = renderFunc(key, result, renderParams);
|
||||||
|
|
||||||
|
if (renderParams.url) {
|
||||||
|
html = `<a href='${renderParams.url}/${pk}/'>` + html + `</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result_html = `
|
||||||
|
<div class='search-result-entry' id='search-result-${key}-${pk}'>
|
||||||
|
${html}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
panel.find(`#search-result-list-${key}`).append(result_html);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Expand results panel
|
||||||
|
panel.find(`#search-result-list-${key}`).toggle();
|
||||||
|
|
||||||
|
// Add callback for "toggle" button
|
||||||
|
panel.find(`#hide-results-${key}`).click(function() {
|
||||||
|
panel.find(`#search-result-list-${key}`).toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add callback for "remove" button
|
||||||
|
panel.find(`#remove-results-${key}`).click(function() {
|
||||||
|
panel.find(`#search-results-${key}`).remove();
|
||||||
|
});
|
||||||
|
}
|
@ -87,18 +87,25 @@
|
|||||||
{% if demo %}
|
{% if demo %}
|
||||||
{% include "navbar_demo.html" %}
|
{% include "navbar_demo.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% include "search_form.html" %}
|
|
||||||
<ul class='navbar-nav flex-row'>
|
<ul class='navbar-nav flex-row'>
|
||||||
|
|
||||||
|
<li class='nav-item me-2'>
|
||||||
|
<button data-bs-toggle='offcanvas' data-bs-target="#offcanvas-search" class='btn position-relative' title='{% trans "Search" %}'>
|
||||||
|
<span class='fas fa-search'></span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
|
||||||
{% if barcodes %}
|
{% if barcodes %}
|
||||||
<li class='nav-item' id='navbar-barcode-li'>
|
<li class='nav-item' id='navbar-barcode-li'>
|
||||||
<button id='barcode-scan' class='btn btn-secondary' title='{% trans "Scan Barcode" %}'>
|
<button id='barcode-scan' class='btn position-relative' title='{% trans "Scan Barcode" %}'>
|
||||||
<span class='fas fa-qrcode'></span>
|
<span class='fas fa-qrcode'></span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<li class='nav-item me-2'>
|
<li class='nav-item me-2'>
|
||||||
<button data-bs-toggle="offcanvas" data-bs-target="#offcanvasRight" class='btn position-relative' title='{% trans "Show Notifications" %}'>
|
<button data-bs-toggle="offcanvas" data-bs-target="#offcanvas-notification" class='btn position-relative' title='{% trans "Show Notifications" %}'>
|
||||||
<span class='fas fa-bell'></span>
|
<span class='fas fa-bell'></span>
|
||||||
<span class="position-absolute top-100 start-100 translate-middle badge rounded-pill bg-danger d-none" id="notification-alert">
|
<span class="position-absolute top-100 start-100 translate-middle badge rounded-pill bg-danger d-none" id="notification-alert">
|
||||||
<span class="visually-hidden">{% trans "New Notifications" %}</span>
|
<span class="visually-hidden">{% trans "New Notifications" %}</span>
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasRight" data-bs-scroll="true" aria-labelledby="offcanvasRightLabel">
|
|
||||||
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvas-notification" data-bs-scroll="true" aria-labelledby="offcanvas-notification-label">
|
||||||
<div class="offcanvas-header">
|
<div class="offcanvas-header">
|
||||||
<h5 id="offcanvasRightLabel">{% trans "Notifications" %}</h5>
|
<h5 id="offcanvas-notification-label">{% trans "Notifications" %}</h5>
|
||||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="offcanvas-body">
|
<div class="offcanvas-body">
|
||||||
@ -11,4 +12,5 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<a href="{% url 'notifications' %}">{% trans "Show all notifications and history" %}</a>
|
<a href="{% url 'notifications' %}">{% trans "Show all notifications and history" %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
43
InvenTree/templates/search.html
Normal file
43
InvenTree/templates/search.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="offcanvas offcanvas-end search-result-panel" tabindex="-1" id="offcanvas-search" data-bs-scroll="true" aria-labelledby="offcanvas-search-label">
|
||||||
|
<div class="offcanvas-header">
|
||||||
|
<form action='{% url "search" %}' method='post' class='d-flex' style='width: 100%;'>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class='input-group'>
|
||||||
|
<input type="text" name='search' class="form-control" aria-label='{% trans "Search" %}' id="search-input" placeholder="{% trans 'Search' %}" autofocus>
|
||||||
|
<button type='submit' id='search-complete' class='btn btn-outline-secondary' title='{% trans "Show full search results" %}'>
|
||||||
|
<span class='fas fa-search'></span>
|
||||||
|
</button>
|
||||||
|
<button id='search-clear' class='btn btn-outline-secondary' title='{% trans "Clear search" %}'>
|
||||||
|
<span class='fas fa-backspace'></span>
|
||||||
|
</button>
|
||||||
|
<!--
|
||||||
|
<button id='search-filter' class="btn btn-outline-secondary" title='{% trans "Filter results" %}'>
|
||||||
|
<span class='fas fa-filter'></span>
|
||||||
|
</button>
|
||||||
|
-->
|
||||||
|
<button id='search-close' class="btn btn-outline-secondary" data-bs-dismiss='offcanvas' title='{% trans "Close search menu" %}'>
|
||||||
|
<span class='fas fa-times icon-red'></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="offcanvas-body">
|
||||||
|
<div id="search-center">
|
||||||
|
<p id='search-pending' class='text-muted' display='none'>
|
||||||
|
<em>{% trans "Searching" %}...</em>
|
||||||
|
<span class='float-right'>
|
||||||
|
<span class='fas fa-spinner fa-spin'></span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p id='search-no-results' class='text-muted'>
|
||||||
|
<em>{% trans "No search results" %}</em>
|
||||||
|
</p>
|
||||||
|
<div id='search-results'>
|
||||||
|
<!-- Search results go here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user