diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css
index 3f6fffe19b..4abba23b09 100644
--- a/InvenTree/InvenTree/static/css/inventree.css
+++ b/InvenTree/InvenTree/static/css/inventree.css
@@ -1018,4 +1018,33 @@ input[type='number']{
a {
text-decoration: none;
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;
}
\ No newline at end of file
diff --git a/InvenTree/InvenTree/static/script/inventree/inventree.js b/InvenTree/InvenTree/static/script/inventree/inventree.js
index d1b49aaf4b..efad99c3ec 100644
--- a/InvenTree/InvenTree/static/script/inventree/inventree.js
+++ b/InvenTree/InvenTree/static/script/inventree/inventree.js
@@ -128,81 +128,6 @@ function inventreeDocReady() {
attachClipboard('.clip-btn', 'modal-about');
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 = `
-
-
- ${item.label}
-
-
- `;
-
- if (user_settings.SEARCH_SHOW_STOCK_LEVELS) {
- html += partStockLabel(
- item.data,
- {
- classes: 'badge-right',
- }
- );
- }
-
- html += '
';
-
- return $('').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
$('.brand-icon').each(function(i, obj) {
loadBrandIcon($(this), $(this).attr('brand_name'));
@@ -231,8 +156,13 @@ function inventreeDocReady() {
stopNotificationWatcher();
});
- $('#offcanvasRight').on('show.bs.offcanvas', openNotificationPanel); // listener for opening the notification panel
- $('#offcanvasRight').on('hidden.bs.offcanvas', closeNotificationPanel); // listener for closing the notification panel
+ // Calbacks for search 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
}
diff --git a/InvenTree/InvenTree/test_views.py b/InvenTree/InvenTree/test_views.py
index 56d8889984..490e91b03e 100644
--- a/InvenTree/InvenTree/test_views.py
+++ b/InvenTree/InvenTree/test_views.py
@@ -72,7 +72,7 @@ class ViewTests(TestCase):
"""
# 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()
diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py
index d795b81472..ec8b891f93 100644
--- a/InvenTree/InvenTree/urls.py
+++ b/InvenTree/InvenTree/urls.py
@@ -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'^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'^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'^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'),
diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py
index 20acd84ce1..bb7de56e99 100644
--- a/InvenTree/common/models.py
+++ b/InvenTree/common/models.py
@@ -1268,20 +1268,62 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
'validator': bool,
},
- 'SEARCH_PREVIEW_RESULTS': {
- 'name': _('Search Preview Results'),
- 'description': _('Number of results to show 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'),
+ 'SEARCH_PREVIEW_SHOW_PARTS': {
+ 'name': _('Search Parts'),
+ 'description': _('Display parts in search preview window'),
'default': True,
'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': {
'name': _("Hide Inactive Parts"),
'description': _('Hide inactive parts in search preview window'),
diff --git a/InvenTree/templates/InvenTree/settings/user_search.html b/InvenTree/templates/InvenTree/settings/user_search.html
index 51df53ee6b..1883110b80 100644
--- a/InvenTree/templates/InvenTree/settings/user_search.html
+++ b/InvenTree/templates/InvenTree/settings/user_search.html
@@ -14,8 +14,16 @@
+ {% 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_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' %}
diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html
index 3791d5f059..d3c8ed8a59 100644
--- a/InvenTree/templates/base.html
+++ b/InvenTree/templates/base.html
@@ -127,9 +127,11 @@
{% endblock %}
+
{% include 'modals.html' %}
{% include 'about.html' %}
{% include "notifications.html" %}
+ {% include "search.html" %}
@@ -186,6 +188,7 @@
+
diff --git a/InvenTree/templates/js/translated/model_renderers.js b/InvenTree/templates/js/translated/model_renderers.js
index e3abe1186f..7be6c954c2 100644
--- a/InvenTree/templates/js/translated/model_renderers.js
+++ b/InvenTree/templates/js/translated/model_renderers.js
@@ -10,7 +10,9 @@
renderCompany,
renderManufacturerPart,
renderOwner,
+ renderPart,
renderPartCategory,
+ renderStockItem,
renderStockLocation,
renderSupplierPart,
*/
@@ -31,7 +33,7 @@
// Renderer for "Company" model
// eslint-disable-next-line no-unused-vars
-function renderCompany(name, data, parameters, options) {
+function renderCompany(name, data, parameters={}, options={}) {
var html = select2Thumbnail(data.image);
@@ -45,7 +47,7 @@ function renderCompany(name, data, parameters, options) {
// Renderer for "StockItem" model
// eslint-disable-next-line no-unused-vars
-function renderStockItem(name, data, parameters, options) {
+function renderStockItem(name, data, parameters={}, options={}) {
var image = blankImage();
@@ -111,7 +113,7 @@ function renderStockItem(name, data, parameters, options) {
// Renderer for "StockLocation" model
// eslint-disable-next-line no-unused-vars
-function renderStockLocation(name, data, parameters, options) {
+function renderStockLocation(name, data, parameters={}, options={}) {
var level = '- '.repeat(data.level);
@@ -133,7 +135,7 @@ function renderStockLocation(name, data, parameters, options) {
}
// eslint-disable-next-line no-unused-vars
-function renderBuild(name, data, parameters, options) {
+function renderBuild(name, data, parameters={}, options={}) {
var image = null;
@@ -154,7 +156,7 @@ function renderBuild(name, data, parameters, options) {
// Renderer for "Part" model
// eslint-disable-next-line no-unused-vars
-function renderPart(name, data, parameters, options) {
+function renderPart(name, data, parameters={}, options={}) {
var html = select2Thumbnail(data.image);
@@ -164,13 +166,14 @@ function renderPart(name, data, parameters, options) {
html += ` - ${data.description} `;
}
- var extra = '';
+ var stock_data = '';
- // Display available part quantity
if (user_settings.PART_SHOW_QUANTITY_IN_FORMS) {
- extra += partStockLabel(data);
+ stock_data = partStockLabel(data);
}
+ var extra = '';
+
if (!data.active) {
extra += `{% trans "Inactive" %} `;
}
@@ -178,6 +181,7 @@ function renderPart(name, data, parameters, options) {
html += `
+ ${stock_data}
${extra}
{% trans "Part ID" %}: ${data.pk}
@@ -188,7 +192,7 @@ function renderPart(name, data, parameters, options) {
// Renderer for "User" model
// eslint-disable-next-line no-unused-vars
-function renderUser(name, data, parameters, options) {
+function renderUser(name, data, parameters={}, options={}) {
var html = `${data.username} `;
@@ -202,7 +206,7 @@ function renderUser(name, data, parameters, options) {
// Renderer for "Owner" model
// eslint-disable-next-line no-unused-vars
-function renderOwner(name, data, parameters, options) {
+function renderOwner(name, data, parameters={}, options={}) {
var html = `${data.name} `;
@@ -223,15 +227,13 @@ function renderOwner(name, data, parameters, options) {
// Renderer for "PurchaseOrder" model
// eslint-disable-next-line no-unused-vars
-function renderPurchaseOrder(name, data, parameters, options) {
- var html = '';
+function renderPurchaseOrder(name, data, parameters={}, options={}) {
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
+ var html = `${prefix}${data.reference} `;
var thumbnail = null;
- html += `${prefix}${data.reference} `;
-
if (data.supplier_detail) {
thumbnail = data.supplier_detail.thumbnail || data.supplier_detail.image;
@@ -257,8 +259,19 @@ function renderPurchaseOrder(name, data, parameters, options) {
// Renderer for "SalesOrder" model
// eslint-disable-next-line no-unused-vars
-function renderSalesOrder(name, data, parameters, options) {
- var html = `${data.reference} `;
+function renderSalesOrder(name, data, parameters={}, options={}) {
+
+ var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
+ var html = `${prefix}${data.reference} `;
+
+ var thumbnail = null;
+
+ if (data.customer_detail) {
+ thumbnail = data.customer_detail.thumbnail || data.customer_detail.image;
+
+ html += ' - ' + select2Thumbnail(thumbnail);
+ html += `${data.customer_detail.name} `;
+ }
if (data.description) {
html += ` - ${data.description} `;
@@ -277,7 +290,7 @@ function renderSalesOrder(name, data, parameters, options) {
// Renderer for "SalesOrderShipment" model
// 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;
@@ -294,7 +307,7 @@ function renderSalesOrderShipment(name, data, parameters, options) {
// Renderer for "PartCategory" model
// eslint-disable-next-line no-unused-vars
-function renderPartCategory(name, data, parameters, options) {
+function renderPartCategory(name, data, parameters={}, options={}) {
var level = '- '.repeat(data.level);
@@ -310,7 +323,7 @@ function renderPartCategory(name, data, parameters, options) {
}
// eslint-disable-next-line no-unused-vars
-function renderPartParameterTemplate(name, data, parameters, options) {
+function renderPartParameterTemplate(name, data, parameters={}, options={}) {
var units = '';
@@ -326,7 +339,7 @@ function renderPartParameterTemplate(name, data, parameters, options) {
// Renderer for "ManufacturerPart" model
// eslint-disable-next-line no-unused-vars
-function renderManufacturerPart(name, data, parameters, options) {
+function renderManufacturerPart(name, data, parameters={}, options={}) {
var manufacturer_image = null;
var part_image = null;
@@ -355,7 +368,7 @@ function renderManufacturerPart(name, data, parameters, options) {
// Renderer for "SupplierPart" model
// eslint-disable-next-line no-unused-vars
-function renderSupplierPart(name, data, parameters, options) {
+function renderSupplierPart(name, data, parameters={}, options={}) {
var supplier_image = null;
var part_image = null;
diff --git a/InvenTree/templates/js/translated/search.js b/InvenTree/templates/js/translated/search.js
new file mode 100644
index 0000000000..8900007c31
--- /dev/null
+++ b/InvenTree/templates/js/translated/search.js
@@ -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(`
+
+ `);
+
+ 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(`
+
+ `);
+
+ results.forEach(function(result) {
+
+ var pk = result.pk || result.id;
+
+ var html = renderFunc(key, result, renderParams);
+
+ if (renderParams.url) {
+ html = `` + html + ` `;
+ }
+
+ var result_html = `
+
+ ${html}
+
+ `;
+
+ 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();
+ });
+}
diff --git a/InvenTree/templates/navbar.html b/InvenTree/templates/navbar.html
index 126376a7dc..d687300eb4 100644
--- a/InvenTree/templates/navbar.html
+++ b/InvenTree/templates/navbar.html
@@ -87,18 +87,25 @@
{% if demo %}
{% include "navbar_demo.html" %}
{% endif %}
- {% include "search_form.html" %}
+
+
+
+
+
+
+
+
{% if barcodes %}
-
+
{% endif %}
-
+
{% trans "New Notifications" %}
diff --git a/InvenTree/templates/notifications.html b/InvenTree/templates/notifications.html
index bec96d1585..e7dfc86998 100644
--- a/InvenTree/templates/notifications.html
+++ b/InvenTree/templates/notifications.html
@@ -1,7 +1,8 @@
{% load i18n %}
-
+
+
\ No newline at end of file
+
+
diff --git a/InvenTree/templates/search.html b/InvenTree/templates/search.html
new file mode 100644
index 0000000000..b43175b4b0
--- /dev/null
+++ b/InvenTree/templates/search.html
@@ -0,0 +1,43 @@
+{% load i18n %}
+
+
+
+
+
+
+ {% trans "Searching" %}...
+
+
+
+
+
+ {% trans "No search results" %}
+
+
+
+
+
+
+
+
\ No newline at end of file