+
{{ 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()