From 731161ad5ca26d09477064f4f3276f6a6ab68533 Mon Sep 17 00:00:00 2001 From: RitvikSardana Date: Fri, 17 Jan 2025 15:39:55 +0530 Subject: [PATCH] fix: handle general category, delete article/category & move to category validations --- desk/src/components/ListRows.vue | 15 +++------- .../knowledge-base/KnowledgeBaseAgent.vue | 28 +++++++++++++++---- desk/src/pages/knowledge-base/NewArticle.vue | 9 +++++- desk/src/router/index.ts | 3 +- desk/src/stores/knowledgeBase.ts | 6 ++-- helpdesk/api/knowledge_base.py | 21 +++++++++++++- .../helpdesk/doctype/hd_article/hd_article.py | 16 +++++++++++ .../hd_article_category.py | 16 +++++++++-- 8 files changed, 89 insertions(+), 25 deletions(-) diff --git a/desk/src/components/ListRows.vue b/desk/src/components/ListRows.vue index e29055c64..b9935127d 100644 --- a/desk/src/components/ListRows.vue +++ b/desk/src/components/ListRows.vue @@ -7,17 +7,10 @@ >
-
- {{ "General" }} - {{ - group.rows.length + - " Article" + - (group.rows.length > 1 ? "s" : "") - }} - -
-
+
{{ group.group.label }} {{ diff --git a/desk/src/pages/knowledge-base/KnowledgeBaseAgent.vue b/desk/src/pages/knowledge-base/KnowledgeBaseAgent.vue index 388ea72bf..9b1b37f7d 100644 --- a/desk/src/pages/knowledge-base/KnowledgeBaseAgent.vue +++ b/desk/src/pages/knowledge-base/KnowledgeBaseAgent.vue @@ -38,6 +38,7 @@ import { Button, confirmDialog, Dropdown, + createResource, } from "frappe-ui"; import { useRouter } from "vue-router"; import { @@ -52,6 +53,7 @@ import ListViewBuilder from "@/components/ListViewBuilder.vue"; import CategoryModal from "@/components/knowledge-base/CategoryModal.vue"; import MoveToCategoryModal from "@/components/knowledge-base/MoveToCategoryModal.vue"; import { createToast } from "@/utils"; +import { Error } from "@/types"; const router = useRouter(); @@ -67,6 +69,12 @@ const editTitle = ref(false); const showCategoryModal = ref(false); const moveToModal = ref(false); +const generalCategory = createResource({ + url: "helpdesk.api.knowledge_base.get_general_category", + auto: true, + cache: ["GeneralCategory"], +}); + const headerOptions = [ { label: "Category", @@ -81,7 +89,15 @@ const headerOptions = [ label: "Article", icon: "file-text", onClick: () => { - router.push({ name: "NewArticle" }); + router.push({ + name: "NewArticle", + params: { + id: generalCategory.data, + }, + query: { + title: "General", + }, + }); }, }, ]; @@ -93,8 +109,10 @@ const groupByActions = [ onClick: (groupedRow) => { router.push({ name: "NewArticle", + params: { + id: groupedRow.group.value, + }, query: { - category: groupedRow.group.value, title: groupedRow.group.label, }, }); @@ -164,9 +182,9 @@ function handleMoveToCategory(category: string) { iconClasses: "text-green-600", }); }, - onError: (error: string) => { + onError: (error: Error) => { createToast({ - title: error, + title: error?.messages?.[0] || error.message, icon: "x", iconClasses: "text-red-600", }); @@ -264,7 +282,7 @@ function handleCategoryDelete(groupedRow) { { onSuccess: () => { createToast({ - title: "Article deleted successfully", + title: "Category deleted successfully", icon: "check", iconClasses: "text-green-600", }); diff --git a/desk/src/pages/knowledge-base/NewArticle.vue b/desk/src/pages/knowledge-base/NewArticle.vue index 245b21a1e..ac2e6aa30 100644 --- a/desk/src/pages/knowledge-base/NewArticle.vue +++ b/desk/src/pages/knowledge-base/NewArticle.vue @@ -93,7 +93,14 @@ const route = useRoute(); const title = ref(""); const content = ref(""); -const categoryId = ref(route.query.category || null); +const props = defineProps({ + id: { + type: String, + required: true, + }, +}); + +const categoryId = ref(props.id || null); const categoryName = computed(() => (route.query.title as string) || ""); function handleCreateArticle() { diff --git a/desk/src/router/index.ts b/desk/src/router/index.ts index 6f13560f1..3be4aff2d 100644 --- a/desk/src/router/index.ts +++ b/desk/src/router/index.ts @@ -161,9 +161,10 @@ const routes = [ props: true, }, { - path: "articles/new", + path: "articles/new/:id", name: "NewArticle", component: () => import("@/pages/knowledge-base/NewArticle.vue"), + props: true, }, { path: "customers", diff --git a/desk/src/stores/knowledgeBase.ts b/desk/src/stores/knowledgeBase.ts index 7aa28e2ff..71cceb86d 100644 --- a/desk/src/stores/knowledgeBase.ts +++ b/desk/src/stores/knowledgeBase.ts @@ -68,8 +68,8 @@ export const moveToCategory = createResource({ }; }, validate({ category, articles }) { - if (!category) throw "Category is required"; - if (!articles) throw "Articles are required"; + if (!category) throw {message:"Category is required"}; + if (!articles) throw {message:"Articles are required"}; }, }); @@ -78,8 +78,6 @@ export const categories = createResource({ cache: ["categories"], }); - - export const categoryName = createResource({ url: "helpdesk.api.knowledge_base.get_category_title", cache: ["categoryName"], diff --git a/helpdesk/api/knowledge_base.py b/helpdesk/api/knowledge_base.py index 48b208e66..8cf61d505 100644 --- a/helpdesk/api/knowledge_base.py +++ b/helpdesk/api/knowledge_base.py @@ -60,7 +60,19 @@ def create_category(title: str): @frappe.whitelist() def move_to_category(category, articles): for article in articles: - frappe.db.set_value("HD Article", article, "category", category) + try: + article_category = frappe.db.get_value("HD Article", article, "category") + category_existing_articles = frappe.db.count( + "HD Article", {"category": article_category} + ) + if category_existing_articles == 1: + frappe.throw("Category must have atleast one article") + return + else: + frappe.db.set_value("HD Article", article, "category", category) + except Exception as e: + frappe.db.rollback() + frappe.throw("Error moving article to category") @frappe.whitelist() @@ -94,6 +106,13 @@ def get_category_articles(category): return articles +@frappe.whitelist() +def get_general_category(): + return frappe.db.get_value( + "HD Article Category", {"category_name": "General"}, "name" + ) + + @frappe.whitelist() def get_category_title(category): return frappe.db.get_value("HD Article Category", category, "category_name") diff --git a/helpdesk/helpdesk/doctype/hd_article/hd_article.py b/helpdesk/helpdesk/doctype/hd_article/hd_article.py index 16c83666a..a0ffec6a3 100644 --- a/helpdesk/helpdesk/doctype/hd_article/hd_article.py +++ b/helpdesk/helpdesk/doctype/hd_article/hd_article.py @@ -7,6 +7,11 @@ class HDArticle(Document): + def validate(self): + if self.has_value_changed("category"): + old_category = self.get_doc_before_save().get("category") + self.check_category_length(old_category) + def before_insert(self): self.author = frappe.session.user @@ -31,6 +36,17 @@ def before_save(self): ) ) + def on_trash(self): + self.check_category_length() + + def check_category_length(self, category=None): + category = category or self.get("category") + if not category: + return + category_articles = frappe.db.count("HD Article", {"category": category}) + if category_articles == 1: + frappe.throw("Category must have atleast one article") + @staticmethod def default_list_data(): columns = [ diff --git a/helpdesk/helpdesk/doctype/hd_article_category/hd_article_category.py b/helpdesk/helpdesk/doctype/hd_article_category/hd_article_category.py index 708481326..b9c66408c 100644 --- a/helpdesk/helpdesk/doctype/hd_article_category/hd_article_category.py +++ b/helpdesk/helpdesk/doctype/hd_article_category/hd_article_category.py @@ -11,7 +11,12 @@ def validate(self): self.validate_default_category() def validate_default_category(self): - if self.has_value_changed("category_name"): + old_doc = self.get_doc_before_save() + if not old_doc: + return + old_value = old_doc.get("category_name") + + if self.has_value_changed("category_name") and old_value == "General": frappe.throw(_("General category name can't be changed")) def on_trash(self): @@ -22,8 +27,15 @@ def on_trash(self): articles = frappe.get_all( "HD Article", filters={"category": self.name}, pluck="name" ) + + general_category = frappe.db.get_value( + "HD Article Category", {"category_name": "General"}, "name" + ) + if not general_category: + return + try: for article in articles: - frappe.db.set_value("HD Article", article, "category", None) + frappe.db.set_value("HD Article", article, "category", general_category) except Exception as e: frappe.db.rollback()