diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index 995c16154c..5aa9f0a40e 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -2,6 +2,7 @@ # License: MIT. See LICENSE import json +from typing import Literal from bs4 import BeautifulSoup @@ -251,6 +252,18 @@ def get_open_count(doctype: str, name: str, items=None): if frappe.flags.in_migrate or frappe.flags.in_install: return {"count": []} + # None of the count queries should take more than 1s individually + frappe.db.set_execution_timeout(1) + + try: + return _get_linked_document_counts(doctype, name, items) + except Exception as e: + if frappe.db.is_statement_timeout(e): + return {"count": []} + raise + + +def _get_linked_document_counts(doctype: str, name: str, items=None): doc = frappe.get_lazy_doc(doctype, name) doc.check_permission() meta = doc.meta @@ -342,18 +355,16 @@ def get_external_links(doctype, name, links): return {"doctype": doctype, "count": total_count, "open_count": open_count} -def get_doc_count(doctype, filters): - return len( - frappe.get_all( - doctype, - fields="name", - filters=filters, - limit=100, - distinct=True, - ignore_ifnull=True, - order_by=None, +def get_doc_count(doctype, filters) -> int | Literal["?"]: + try: + docs = frappe.get_all( + doctype, filters=filters, limit=100, distinct=True, ignore_ifnull=True, order_by=None ) - ) + return len(docs) + except Exception as e: + if frappe.db.is_statement_timeout(e): # Skip fetching correct count if it's too slow + return "?" + raise def get_dynamic_link_filters(doctype, links, fieldname): diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index f381543231..ddb8ba2e02 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -457,18 +457,14 @@ frappe.ui.form.Dashboard = class FormDashboard { $.each(count.internal_links_found, function (i, d) { me.frm.dashboard.set_badge_count_for_internal_link( d.doctype, - cint(d.open_count), - cint(d.count), + d.open_count, + d.count, d.names ); }); $.each(count.external_links_found, function (i, d) { - me.frm.dashboard.set_badge_count_for_external_link( - d.doctype, - cint(d.open_count), - cint(d.count) - ); + me.frm.dashboard.set_badge_count_for_external_link(d.doctype, d.open_count, d.count); }); } @@ -499,14 +495,20 @@ frappe.ui.form.Dashboard = class FormDashboard { $link .find(".open-notification") .removeClass("hidden") - .html(open_count > 99 ? "99+" : open_count); + .html(cint(open_count) > 99 ? "99+" : open_count); } if (count) { $link .find(".count") .removeClass("hidden") - .text(count > 99 ? "99+" : count); + .text(cint(count) > 99 ? "99+" : count) + .attr( + "title", + count != "?" + ? __("Count of linked documents") + : __("Accurate count can not be fetched, click here to view all documents") + ); } }