feat: Search UI

- Search UI with dropdown results
- Client class to handle Product Search actions and results
- Integrated Search bar into all-products and item group pages
- Run db search without redisearch
- Cleanup: [Search] change decorator names and variables
- Sider fixes
This commit is contained in:
marination
2021-06-01 12:44:49 +05:30
parent 4f73deeb78
commit acfdc6f22e
18 changed files with 376 additions and 349 deletions

View File

@@ -2,7 +2,16 @@
{% extends "templates/web.html" %}
{% block header %}
<!-- <h2>{{ title }}</h2> -->
<div class="row mb-6" style="width: 65vw">
<div class="mb-6 col-4 order-1">{{ title }}</div>
<div class="input-group mb-6 col-8 order-2">
<div class="dropdown w-100" id="dropdownMenuSearch">
<input type="search" name="query" id="search-box" class="form-control" placeholder="Search for products..." aria-label="Product" aria-describedby="button-addon2">
<!-- Results dropdown rendered in product_search.js -->
</div>
</div>
</div>
{% endblock header %}
{% block script %}
@@ -19,7 +28,7 @@
<div class="item-group-content" itemscope itemtype="http://schema.org/Product"
data-item-group="{{ name }}">
<div class="item-group-slideshow">
{% if slideshow %}<!-- slideshow -->
{% if slideshow %} <!-- slideshow -->
{{ web_block(
"Hero Slider",
values=slideshow,
@@ -28,8 +37,8 @@
add_bottom_padding=0,
) }}
{% endif %}
<h2 class="mt-3">{{ title }}</h2>
{% if description %}<!-- description -->
{% if description %} <!-- description -->
<div class="item-group-description text-muted mb-5" itemprop="description">{{ description or ""}}</div>
{% endif %}
</div>

View File

@@ -163,7 +163,7 @@ $.extend(shopping_cart, {
item_code: item_code,
qty: 0
});
})
});
},
render_tax_row: function($cart_taxes, doc, shipping_rules) {

View File

@@ -6,16 +6,14 @@ from frappe.utils import cstr, nowdate, cint
from erpnext.setup.doctype.item_group.item_group import get_item_for_list_in_html
from erpnext.e_commerce.shopping_cart.product_info import set_product_info_for_website
# For SEARCH -------
from redisearch import AutoCompleter, Client, Query
from erpnext.e_commerce.website_item_indexing import (
is_search_module_loaded,
WEBSITE_ITEM_INDEX,
WEBSITE_ITEM_INDEX,
WEBSITE_ITEM_NAME_AUTOCOMPLETE,
WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE,
make_key
)
# -----------------
no_cache = 1
@@ -35,30 +33,29 @@ def get_product_list(search=None, start=0, limit=12):
def get_product_data(search=None, start=0, limit=12):
# limit = 12 because we show 12 items in the grid view
# base query
query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group,
I.description, I.web_long_description as website_description, I.is_stock_item,
case when (S.actual_qty - S.reserved_qty) > 0 then 1 else 0 end as in_stock, I.website_warehouse,
I.has_batch_no
from `tabItem` I
left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse
where (I.show_in_website = 1)
and I.disabled = 0
and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s)"""
query = """
Select
web_item_name, item_name, item_code, brand, route,
website_image, thumbnail, item_group,
description, web_long_description as website_description,
website_warehouse, ranking
from `tabWebsite Item`
where published = 1
"""
# search term condition
if search:
query += """ and (I.web_long_description like %(search)s
or I.description like %(search)s
or I.item_name like %(search)s
or I.name like %(search)s)"""
query += """ and (item_name like %(search)s
or web_item_name like %(search)s
or brand like %(search)s
or web_long_description like %(search)s)"""
search = "%" + cstr(search) + "%"
# order by
query += """ order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (cint(start), cint(limit))
query += """ order by ranking asc, modified desc limit %s, %s""" % (cint(start), cint(limit))
return frappe.db.sql(query, {
"search": search,
"today": nowdate()
"search": search
}, as_dict=1)
@frappe.whitelist(allow_guest=True)
@@ -80,8 +77,8 @@ def search(query, limit=10, fuzzy_search=True):
ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=red)
client = Client(make_key(WEBSITE_ITEM_INDEX), conn=red)
suggestions = ac.get_suggestions(
query,
num=limit,
query,
num=limit,
fuzzy= fuzzy_search and len(query) > 4 # Fuzzy on length < 3 can be real slow
)
@@ -111,11 +108,19 @@ def convert_to_dict(redis_search_doc):
@frappe.whitelist(allow_guest=True)
def get_category_suggestions(query):
search_results = {"from_redisearch": True, "results": []}
search_results = {"results": []}
if not is_search_module_loaded():
# Redisearch module not loaded
search_results["from_redisearch"] = False
# Redisearch module not loaded, query db
categories = frappe.db.get_all(
"Item Group",
filters={
"name": ["like", "%{0}%".format(query)],
"show_in_website": 1
},
fields=["name", "route"]
)
search_results['results'] = categories
return search_results
if not query:
@@ -125,5 +130,5 @@ def get_category_suggestions(query):
suggestions = ac.get_suggestions(query, num=10)
search_results['results'] = [s.string for s in suggestions]
return search_results