feat: improved search results in command palette
This commit is contained in:
29
lms/command_palette.py
Normal file
29
lms/command_palette.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import frappe
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def search_sqlite(query: str):
|
||||
from lms.sqlite import LearningSearch, LearningSearchIndexMissingError
|
||||
|
||||
search = LearningSearch()
|
||||
|
||||
try:
|
||||
result = search.search(query)
|
||||
except LearningSearchIndexMissingError:
|
||||
return []
|
||||
|
||||
groups = {}
|
||||
print(result)
|
||||
for r in result["results"]:
|
||||
doctype = r["doctype"]
|
||||
|
||||
if doctype == "LMS Course":
|
||||
groups.setdefault("Courses", []).append(r)
|
||||
elif doctype == "LMS Batch":
|
||||
groups.setdefault("Batches", []).append(r)
|
||||
|
||||
out = []
|
||||
for key in groups:
|
||||
out.append({"title": key, "items": groups[key]})
|
||||
|
||||
return out
|
||||
@@ -64,6 +64,9 @@ after_install = "lms.install.after_install"
|
||||
after_sync = "lms.install.after_sync"
|
||||
before_uninstall = "lms.install.before_uninstall"
|
||||
setup_wizard_requires = "assets/lms/js/setup_wizard.js"
|
||||
after_migrate = [
|
||||
"lms.sqlite.build_index_in_background",
|
||||
]
|
||||
|
||||
# Desk Notifications
|
||||
# ------------------
|
||||
@@ -112,6 +115,9 @@ doc_events = {
|
||||
# Scheduled Tasks
|
||||
# ---------------
|
||||
scheduler_events = {
|
||||
"all": [
|
||||
"lms.sqlite.build_index_in_background",
|
||||
],
|
||||
"hourly": [
|
||||
"lms.lms.doctype.lms_certificate_request.lms_certificate_request.schedule_evals",
|
||||
"lms.lms.api.update_course_statistics",
|
||||
@@ -251,3 +257,5 @@ add_to_apps_screen = [
|
||||
"has_permission": "lms.lms.api.check_app_permission",
|
||||
}
|
||||
]
|
||||
|
||||
sqlite_search = ["lms.sqlite.LearningSearch"]
|
||||
|
||||
@@ -76,6 +76,8 @@
|
||||
"default": "0",
|
||||
"fieldname": "published",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Published"
|
||||
},
|
||||
{
|
||||
@@ -152,8 +154,6 @@
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"options": "In Progress\nUnder Review\nApproved",
|
||||
"read_only": 1
|
||||
@@ -313,7 +313,7 @@
|
||||
}
|
||||
],
|
||||
"make_attachments_public": 1,
|
||||
"modified": "2025-10-13 15:08:11.734204",
|
||||
"modified": "2025-11-25 11:35:17.924569",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Course",
|
||||
|
||||
122
lms/sqlite.py
Normal file
122
lms/sqlite.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from contextlib import suppress
|
||||
|
||||
import frappe
|
||||
from frappe.search.sqlite_search import SQLiteSearch, SQLiteSearchIndexMissingError
|
||||
from frappe.utils import update_progress_bar
|
||||
from redis.exceptions import ResponseError
|
||||
|
||||
|
||||
class LearningSearch(SQLiteSearch):
|
||||
INDEX_NAME = "learning.db"
|
||||
|
||||
INDEX_SCHEMA = {
|
||||
"metadata_fields": ["category", "owner", "published"],
|
||||
"tokenizer": "unicode61 remove_diacritics 2 tokenchars '-_'",
|
||||
}
|
||||
|
||||
INDEXABLE_DOCTYPES = {
|
||||
"LMS Course": {
|
||||
"fields": [
|
||||
"name",
|
||||
"title",
|
||||
{"content": "description"},
|
||||
"short_introduction",
|
||||
"published",
|
||||
"category",
|
||||
"owner",
|
||||
{"modified": "published_on"},
|
||||
],
|
||||
},
|
||||
"LMS Batch": {
|
||||
"fields": [
|
||||
"name",
|
||||
"title",
|
||||
"description",
|
||||
{"content": "batch_details"},
|
||||
"published",
|
||||
"category",
|
||||
"owner",
|
||||
{"modified": "start_date"},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
DOCTYPE_FIELDS = {
|
||||
"LMS Course": [
|
||||
"name",
|
||||
"title",
|
||||
"description",
|
||||
"short_introduction",
|
||||
"category",
|
||||
"creation",
|
||||
"modified",
|
||||
"owner",
|
||||
],
|
||||
"LMS Batch": [
|
||||
"name",
|
||||
"title",
|
||||
"description",
|
||||
"batch_details",
|
||||
"category",
|
||||
"creation",
|
||||
"modified",
|
||||
"owner",
|
||||
],
|
||||
}
|
||||
|
||||
def can_create_course(self, roles):
|
||||
return "Course Creator" in roles or "Moderator" in roles
|
||||
|
||||
def can_create_batch(self, roles):
|
||||
return "Batch Evaluator" in roles or "Moderator" in roles
|
||||
|
||||
def get_records(self, doctype):
|
||||
records = []
|
||||
roles = frappe.get_roles()
|
||||
filters = {}
|
||||
|
||||
if doctype == "LMS Course":
|
||||
if not self.can_create_course(roles):
|
||||
filters = {"published": 1}
|
||||
|
||||
if doctype == "LMS Batch":
|
||||
if not self.can_create_batch(roles):
|
||||
filters = {"published": 1}
|
||||
|
||||
records = frappe.db.get_all(doctype, filters=filters, fields=self.DOCTYPE_FIELDS[doctype])
|
||||
for record in records:
|
||||
record["doctype"] = doctype
|
||||
|
||||
return records
|
||||
|
||||
def build_index(self):
|
||||
try:
|
||||
super().build_index()
|
||||
except Exception as e:
|
||||
frappe.throw(e)
|
||||
|
||||
def get_search_filters(self):
|
||||
roles = frappe.get_roles()
|
||||
if not (self.can_create_course(roles) and self.can_create_batch(roles)):
|
||||
return {"published": 1}
|
||||
return {}
|
||||
|
||||
|
||||
class LearningSearchIndexMissingError(SQLiteSearchIndexMissingError):
|
||||
pass
|
||||
|
||||
|
||||
def build_index():
|
||||
search = LearningSearch()
|
||||
search.build_index()
|
||||
|
||||
|
||||
def build_index_in_background():
|
||||
if not frappe.cache().get_value("learning_search_indexing_in_progress"):
|
||||
frappe.enqueue(build_index, queue="long")
|
||||
|
||||
|
||||
def build_index_if_not_exists():
|
||||
search = LearningSearch()
|
||||
if not search.index_exists():
|
||||
build_index()
|
||||
Reference in New Issue
Block a user