From 013267655340a8183c0e40baa776a240d3d096cc Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 12 Feb 2026 12:18:05 +0530 Subject: [PATCH 01/70] fix: consider email account for communication duplicate check --- frappe/core/doctype/communication/communication.py | 2 +- frappe/email/doctype/email_account/test_email_account.py | 6 ++++-- frappe/email/receive.py | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 59aefc53bf..16dae174ec 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -419,7 +419,7 @@ class Communication(Document, CommunicationEmailMixin): # Skip timeline links if a "Sent" communication already exists # else will create duplicate timeline entries if self.sent_or_received == "Received" and self.find_one_by_filters( - message_id=self.message_id, sent_or_received="Sent" + message_id=self.message_id, email_account=self.email_account, sent_or_received="Sent" ): return diff --git a/frappe/email/doctype/email_account/test_email_account.py b/frappe/email/doctype/email_account/test_email_account.py index c6f88c2862..93b5c36209 100644 --- a/frappe/email/doctype/email_account/test_email_account.py +++ b/frappe/email/doctype/email_account/test_email_account.py @@ -521,12 +521,14 @@ class TestInboundMail(IntegrationTestCase): def test_mail_exist_validation(self): """Do not create communication record if the mail is already downloaded into the system.""" + email_account = frappe.get_doc("Email Account", "_Test Email Account 1") mail_content = self.get_test_mail(fname="incoming-1.raw") message_id = Email(mail_content).message_id # Create new communication record in DB - communication = self.new_communication(message_id=message_id, sent_or_received="Received") + communication = self.new_communication( + message_id=message_id, email_account=email_account.name, sent_or_received="Received" + ) - email_account = frappe.get_doc("Email Account", "_Test Email Account 1") inbound_mail = InboundMail(mail_content, email_account, 12345, 1) new_communication = inbound_mail.process() diff --git a/frappe/email/receive.py b/frappe/email/receive.py index 8d1c64217a..ce52e98188 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -721,7 +721,10 @@ class InboundMail(Email): return return Communication.find_one_by_filters( - message_id=self.message_id, sent_or_received="Received", order_by="creation DESC" + message_id=self.message_id, + email_account=self.email_account.name, + sent_or_received="Received", + order_by="creation DESC", ) def is_sender_same_as_receiver(self): From 8e3bd72ef73eb777d814cd0829c734dea7e2a663 Mon Sep 17 00:00:00 2001 From: Sumit Jain Date: Thu, 12 Feb 2026 12:37:53 +0530 Subject: [PATCH 02/70] fix(workflow): add function to retrieve user who set workflow state --- .../workflow_action/workflow_action.py | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/frappe/workflow/doctype/workflow_action/workflow_action.py b/frappe/workflow/doctype/workflow_action/workflow_action.py index 8e04f89500..b3e78f8efa 100644 --- a/frappe/workflow/doctype/workflow_action/workflow_action.py +++ b/frappe/workflow/doctype/workflow_action/workflow_action.py @@ -198,17 +198,57 @@ def return_action_confirmation_page(doc, action, action_link, alert_doc_change=F def return_link_expired_page(doc, doc_workflow_state): + user_full_name = get_user_who_set_workflow_state(doc, doc_workflow_state) or frappe.get_value( + "User", doc.get("modified_by"), "full_name" + ) frappe.respond_as_web_page( _("Link Expired"), _("Document {0} has been set to state {1} by {2}").format( frappe.bold(doc.get("name")), frappe.bold(doc_workflow_state), - frappe.bold(frappe.get_value("User", doc.get("modified_by"), "full_name")), + frappe.bold(user_full_name), ), indicator_color="blue", ) +def get_user_who_set_workflow_state(doc, doc_workflow_state): + """Get the full name of the user who triggered the workflow action that set the document to the given state. + Falls back to None if no completed Workflow Action is found (e.g. state was set without workflow). + """ + workflow_name = get_workflow_name(doc.get("doctype")) + if not workflow_name: + return None + + # Get states that have a transition to the current workflow state + from_states = frappe.get_all( + "Workflow Transition", + filters={"parent": workflow_name, "next_state": doc_workflow_state}, + pluck="state", + ) + if not from_states: + return None + + # Find the most recently completed Workflow Action that led to this state + WorkflowAction = DocType("Workflow Action") + completed_by = ( + frappe.qb.from_(WorkflowAction) + .select(WorkflowAction.completed_by) + .where( + (WorkflowAction.reference_doctype == doc.get("doctype")) + & (WorkflowAction.reference_name == doc.get("name")) + & (WorkflowAction.status == "Completed") + & (WorkflowAction.workflow_state.isin(from_states)) + ) + .orderby(WorkflowAction.modified, order=frappe.qb.desc) + .limit(1) + ).run() + + if completed_by and completed_by[0][0]: + return frappe.get_value("User", completed_by[0][0], "full_name") + return None + + def update_completed_workflow_actions(doc, user=None, workflow=None, workflow_state=None): allowed_roles = get_allowed_roles(user, workflow, workflow_state) # There is no transaction leading upto this state From 697978c8f3aa2ad192a518dc4e9d394eaf4dcb27 Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Fri, 13 Feb 2026 21:37:57 +0530 Subject: [PATCH 03/70] fix(website_404): cache website 404 results wrt to users fixes #37007 --- frappe/website/page_renderers/not_found_page.py | 2 +- frappe/website/path_resolver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/website/page_renderers/not_found_page.py b/frappe/website/page_renderers/not_found_page.py index 704dca77d1..1898d7dece 100644 --- a/frappe/website/page_renderers/not_found_page.py +++ b/frappe/website/page_renderers/not_found_page.py @@ -21,7 +21,7 @@ class NotFoundPage(TemplatePage): def render(self): if self.can_cache_404(): - frappe.cache.hset("website_404", self.request_url, True) + frappe.cache.hset("website_404", f"{frappe.session.user}|{self.request_url}", True) return super().render() def can_cache_404(self): diff --git a/frappe/website/path_resolver.py b/frappe/website/path_resolver.py index 0a2e302118..929438e055 100644 --- a/frappe/website/path_resolver.py +++ b/frappe/website/path_resolver.py @@ -35,7 +35,7 @@ class PathResolver: return "desk", TemplatePage("desk", self.http_status_code) # check if the request url is in 404 list - if request.url and can_cache() and frappe.cache.hget("website_404", request.url): + if request.url and can_cache() and frappe.cache.hget("website_404", f"{frappe.session.user}|{request.url}"): return self.path, NotFoundPage(self.path) try: From a534936726adaaaa5d6b44dfacd036659b2c67df Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Mon, 16 Feb 2026 22:15:01 +0530 Subject: [PATCH 04/70] Revert "fix(website_404): cache website 404 results wrt to users" This reverts commit 697978c8f3aa2ad192a518dc4e9d394eaf4dcb27. --- frappe/website/page_renderers/not_found_page.py | 2 +- frappe/website/path_resolver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/website/page_renderers/not_found_page.py b/frappe/website/page_renderers/not_found_page.py index 1898d7dece..704dca77d1 100644 --- a/frappe/website/page_renderers/not_found_page.py +++ b/frappe/website/page_renderers/not_found_page.py @@ -21,7 +21,7 @@ class NotFoundPage(TemplatePage): def render(self): if self.can_cache_404(): - frappe.cache.hset("website_404", f"{frappe.session.user}|{self.request_url}", True) + frappe.cache.hset("website_404", self.request_url, True) return super().render() def can_cache_404(self): diff --git a/frappe/website/path_resolver.py b/frappe/website/path_resolver.py index 929438e055..0a2e302118 100644 --- a/frappe/website/path_resolver.py +++ b/frappe/website/path_resolver.py @@ -35,7 +35,7 @@ class PathResolver: return "desk", TemplatePage("desk", self.http_status_code) # check if the request url is in 404 list - if request.url and can_cache() and frappe.cache.hget("website_404", f"{frappe.session.user}|{request.url}"): + if request.url and can_cache() and frappe.cache.hget("website_404", request.url): return self.path, NotFoundPage(self.path) try: From 9dcaab96eef44c54aa3e7d53ae9afc30f21357cb Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Mon, 16 Feb 2026 23:41:32 +0530 Subject: [PATCH 05/70] fix(website_404): skip caching 404 for pages with permission checks --- .../website/page_renderers/not_found_page.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/frappe/website/page_renderers/not_found_page.py b/frappe/website/page_renderers/not_found_page.py index 704dca77d1..9b980f5d51 100644 --- a/frappe/website/page_renderers/not_found_page.py +++ b/frappe/website/page_renderers/not_found_page.py @@ -2,6 +2,7 @@ import os from urllib.parse import urlparse import frappe +from frappe.website.page_renderers.document_page import _find_matching_document_webview from frappe.website.page_renderers.template_page import TemplatePage from frappe.website.utils import can_cache @@ -26,10 +27,26 @@ class NotFoundPage(TemplatePage): def can_cache_404(self): # do not cache 404 for custom homepages - return can_cache() and self.request_url and not self.is_custom_home_page() + # also skip caching docs with website permission checks (access is dynamic) + return ( + can_cache() + and self.request_url + and not self.is_custom_home_page() + and not self.has_website_permission_check() + ) def is_custom_home_page(self): url_parts = urlparse(self.request_url) request_url = os.path.splitext(url_parts.path)[0] request_path = os.path.splitext(self.request_path)[0] return request_url in HOMEPAGE_PATHS and request_path not in HOMEPAGE_PATHS + + def has_website_permission_check(self): + request_path = os.path.splitext(self.request_path)[0] + if not (document := _find_matching_document_webview(request_path)): + return False + doctype, docname = document + doc = frappe.get_cached_doc(doctype, docname) + return hasattr(doc, "has_website_permission") or bool( + frappe.get_hooks("has_website_permission", {}).get(doctype) + ) From b98396f4f407e1a2e5d66b6c8b230f3ec7de1903 Mon Sep 17 00:00:00 2001 From: Shrihari Mahabal Date: Mon, 23 Feb 2026 11:54:09 +0530 Subject: [PATCH 06/70] fix: fix: add doc button for long doctype name --- frappe/public/js/frappe/list/list_view.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index d9c6514556..6473db896e 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -291,8 +291,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { set_primary_action() { if (this.can_create && !frappe.boot.read_only) { const doctype_name = __(frappe.router.doctype_layout) || __(this.doctype); + const full_label = __("Add {0}", [doctype_name], "Primary action in list view"); const create_button = this.page.set_primary_action( - __("Add {0}", [doctype_name], "Primary action in list view"), + full_label, () => { if (this.settings.primary_action) { this.settings.primary_action(); @@ -304,12 +305,32 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { ); if (frappe.is_mobile()) { create_button.append(__("Add")); + } else { + this._trim_primary_action_if_overflow(create_button, full_label); } } else { this.page.clear_primary_action(); } } + _trim_primary_action_if_overflow(btn, full_label) { + const container = this.page.wrapper.find(".page-head-content")[0]; + if (!container || !btn[0]) return; + const containerRect = container.getBoundingClientRect(); + const btnRect = btn[0].getBoundingClientRect(); + if (btnRect.right > containerRect.right) { + const short_label = __("Add"); + btn.attr("title", full_label) + .tooltip({ delay: { show: 600, hide: 100 }, trigger: "hover" }) + .html( + `${frappe.utils.icon( + "add", + "xs" + )} ` + ); + } + } + make_new_doc() { const doctype = this.doctype; const options = {}; From bbf8f4d75b7f5e9dcc3f2651b9b10c3dcb2a130f Mon Sep 17 00:00:00 2001 From: Safwan Samsudeen Date: Mon, 23 Feb 2026 14:41:36 +0530 Subject: [PATCH 07/70] fix: add id to file preview --- frappe/core/doctype/file/file.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frappe/core/doctype/file/file.js b/frappe/core/doctype/file/file.js index f3f1380855..6495aa4c1b 100644 --- a/frappe/core/doctype/file/file.js +++ b/frappe/core/doctype/file/file.js @@ -54,14 +54,14 @@ frappe.ui.form.on("File", { `); } else if (frappe.utils.is_video_file(frm.doc.file_url)) { $preview = $(`
`); @@ -72,14 +72,16 @@ frappe.ui.form.on("File", { style="background:#323639;" width="100%" height="1190" - src="${frappe.utils.escape_html(frm.doc.file_url)}" type="application/pdf" + src="${frappe.utils.escape_html(frm.doc.file_url + "?fid=" + frm.doc.name)}" type="application/pdf" > `); } else if (file_extension === "mp3") { $preview = $(`
`); From 967edf99806c94fec83356c413310d4c8b7fe66d Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Mon, 23 Feb 2026 15:09:06 +0530 Subject: [PATCH 08/70] fix: user action designs --- .../js/frappe/form/sidebar/form_sidebar.js | 19 +++-- .../frappe/form/templates/form_sidebar.html | 10 ++- frappe/public/scss/desk/form_sidebar.scss | 80 +++++++++++++++++++ 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/form/sidebar/form_sidebar.js b/frappe/public/js/frappe/form/sidebar/form_sidebar.js index 29f26b76db..ab02e96ab1 100644 --- a/frappe/public/js/frappe/form/sidebar/form_sidebar.js +++ b/frappe/public/js/frappe/form/sidebar/form_sidebar.js @@ -26,6 +26,7 @@ frappe.ui.form.Sidebar = class { .appendTo(this.page.sidebar.empty()); this.user_actions = this.sidebar.find(".user-actions"); + this.user_actions_list = this.sidebar.find(".user-actions-list"); this.image_section = this.sidebar.find(".sidebar-image-section"); this.image_wrapper = this.image_section.find(".sidebar-image-wrapper"); this.make_assignments(); @@ -245,19 +246,23 @@ frappe.ui.form.Sidebar = class { } add_user_action(label, click) { - return $("") - .html(label) - .appendTo( - $('
').appendTo( - this.user_actions.removeClass("hidden") - ) + const parent = this.user_actions_list.length ? this.user_actions_list : this.user_actions; + this.user_actions.removeClass("hidden"); + const row = $('
').appendTo(parent); + + return $('
') + .html( + `${label} + ${frappe.utils.icon("external-link", "sm")}` ) + .appendTo(row) .on("click", click); } clear_user_actions() { this.user_actions.addClass("hidden"); - this.user_actions.find(".user-action-row").remove(); + const parent = this.user_actions_list.length ? this.user_actions_list : this.user_actions; + parent.find(".user-action-row").remove(); } refresh_image() {} diff --git a/frappe/public/js/frappe/form/templates/form_sidebar.html b/frappe/public/js/frappe/form/templates/form_sidebar.html index a43117a67d..30446fe72b 100644 --- a/frappe/public/js/frappe/form/templates/form_sidebar.html +++ b/frappe/public/js/frappe/form/templates/form_sidebar.html @@ -1,4 +1,3 @@ - + diff --git a/frappe/public/js/frappe/ui/user_onboarding/user_onboarding.bundle.js b/frappe/public/js/frappe/ui/user_onboarding/user_onboarding.bundle.js index c75170d28b..3ed2215733 100644 --- a/frappe/public/js/frappe/ui/user_onboarding/user_onboarding.bundle.js +++ b/frappe/public/js/frappe/ui/user_onboarding/user_onboarding.bundle.js @@ -67,7 +67,7 @@ function addStyles() { position: fixed; right: 24px; bottom: 24px; - width: 380px; + width: 310px; max-height: 80vh; background: #fff; border-radius: 16px; From 88da896790801b3334b5b8150709c0b68bec8a02 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 25 Feb 2026 17:27:24 +0530 Subject: [PATCH 60/70] fix: Translate user facing string --- frappe/public/js/frappe/views/workspace/workspace.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index 2be9be9ac0..8ecde380be 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -688,7 +688,7 @@ frappe.views.Workspace = class Workspace { default_block.push({ type: "paragraph", data: { - text: `Click on ${frappe.utils.icon("ellipsis")} to edit`, + text: __("Click on {0} to edit", [frappe.utils.icon("ellipsis")]), }, }); } From c0184e96bd010316563c4c9ad54ec22e980b19c6 Mon Sep 17 00:00:00 2001 From: sokumon Date: Wed, 25 Feb 2026 17:31:55 +0530 Subject: [PATCH 61/70] fix(minor): folder icon styles --- frappe/desk/page/desktop/desktop.css | 4 ++-- frappe/desk/page/desktop/desktop.js | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/frappe/desk/page/desktop/desktop.css b/frappe/desk/page/desktop/desktop.css index 1b1c98e919..ef5e4e6062 100644 --- a/frappe/desk/page/desktop/desktop.css +++ b/frappe/desk/page/desktop/desktop.css @@ -2,7 +2,7 @@ --desktop-blur: blur(10.2px); --desktop-modal-width: 590px; --desktop-modal-height: 450px; - --folder-thumbnail-icon-height: 12px; + --folder-thumbnail-icon-height: 16px; --desktop-icon-dimension: 54px; --folder-icon-background-color: var(--surface-gray-1); --desktop-modal-radius: 30px; @@ -368,7 +368,7 @@ :root { --desktop-icon-dimension: 50px; --desktop-icon-container: 117px; - --folder-thumbnail-icon-height:17px; + --folder-thumbnail-icon-height:15px; } .desktop-container { diff --git a/frappe/desk/page/desktop/desktop.js b/frappe/desk/page/desktop/desktop.js index 8147000152..514af59374 100644 --- a/frappe/desk/page/desktop/desktop.js +++ b/frappe/desk/page/desktop/desktop.js @@ -1086,11 +1086,6 @@ class DesktopIcon { this.folder_grid = new DesktopIconGrid({ wrapper: this.folder_wrapper, icons_data: this.child_icons, - row_size: 3, - page_size: { - row: 3, - col: 3, - }, in_folder: true, in_modal: false, no_dragging: true, From f9f06dbb9bf8426f7267207dbebfafbe0216d07e Mon Sep 17 00:00:00 2001 From: Akash Tom Date: Wed, 25 Feb 2026 18:46:14 +0530 Subject: [PATCH 62/70] fix: check for fieldname while setting open count --- frappe/public/js/frappe/form/dashboard.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index 55015a5103..5c0ad48de3 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -417,10 +417,14 @@ frappe.ui.form.Dashboard = class FormDashboard { } set_open_count() { + const has_fieldname = + this.data.fieldname || + (this.data.transactions && this.data.transactions.some((group) => group.fieldnames)); + if ( !this.data || !this.data.transactions || - !this.data.fieldname || + !has_fieldname || this.frm.is_new() || this._fetched_counts ) { From d4338a1cd9d821d39377f8c79060aec70b9d99b8 Mon Sep 17 00:00:00 2001 From: Akash Tom Date: Wed, 25 Feb 2026 20:45:17 +0530 Subject: [PATCH 63/70] fix: populate child table with linked field --- frappe/public/js/frappe/form/dashboard.js | 3 +-- frappe/public/js/frappe/form/form.js | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index 5c0ad48de3..0e8413f98b 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -418,8 +418,7 @@ frappe.ui.form.Dashboard = class FormDashboard { set_open_count() { const has_fieldname = - this.data.fieldname || - (this.data.transactions && this.data.transactions.some((group) => group.fieldnames)); + this.data.fieldname || this.data.transactions?.some((group) => group.fieldnames); if ( !this.data || diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 26f45e6213..2570864ee3 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -2050,6 +2050,9 @@ frappe.ui.form.Form = class FrappeForm { if (df.fieldname === fieldname && isLinkToParent) { new_doc[df.fieldname] = me.doc.name; } + if (df.fieldtype === "Table" && df.options && df.reqd) { + me.set_link_field(df.options, new_doc[df.fieldname][0]); + } return; } From aa9093ba569931e6f5d5c81ebe83adfba14ab890 Mon Sep 17 00:00:00 2001 From: Akash Tom Date: Wed, 25 Feb 2026 21:24:00 +0530 Subject: [PATCH 64/70] revert: f9f06dbb9bf8426f7267207dbebfafbe0216d07e --- frappe/public/js/frappe/form/dashboard.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index 0e8413f98b..55015a5103 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -417,13 +417,10 @@ frappe.ui.form.Dashboard = class FormDashboard { } set_open_count() { - const has_fieldname = - this.data.fieldname || this.data.transactions?.some((group) => group.fieldnames); - if ( !this.data || !this.data.transactions || - !has_fieldname || + !this.data.fieldname || this.frm.is_new() || this._fetched_counts ) { From c554641e58b570c54f47c74f77e5521536dad995 Mon Sep 17 00:00:00 2001 From: sokumon Date: Thu, 26 Feb 2026 01:58:41 +0530 Subject: [PATCH 65/70] chore: update pypdf --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d0bf7066b3..306aab4d3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ # We depend on internal attributes, # do NOT add loose requirements on PyMySQL versions. "PyMySQL==1.1.2", - "pypdf==6.7.1", + "pypdf==6.7.2", "PyPika @ git+https://github.com/frappe/pypika@2c50e6142b2d61d2d243e466fdd5dc03b3d918f2", "mysqlclient==2.2.7", "PyQRCode~=1.2.1", From 85464f7031e7d7e8005144334e540569df099bc8 Mon Sep 17 00:00:00 2001 From: sokumon Date: Thu, 26 Feb 2026 01:37:23 +0530 Subject: [PATCH 66/70] fix: business hours in popup,theme and apps for which to show --- frappe/public/js/billing.bundle.js | 10 +++++++--- frappe/public/js/frappe/utils/utils.js | 12 ++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/billing.bundle.js b/frappe/public/js/billing.bundle.js index c9bf512844..79e0609c58 100644 --- a/frappe/public/js/billing.bundle.js +++ b/frappe/public/js/billing.bundle.js @@ -89,13 +89,17 @@ function openFrappeCloudDashboard() { } function addChatBubble() { - if (checkBusinessHours()) { + const all_apps = frappe.utils.get_installed_apps(); + const desk_apps = ["erpnext", "hrms"]; + + const apps_allowed = frappe.utils.is_sub_array(all_apps, desk_apps); + if (checkBusinessHours && apps_allowed) { let chat_banner = document.createElement("script"); chat_banner.innerHTML = '(function(d,t){var BASE_URL="https://chat.frappe.cloud";var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src=BASE_URL+"/packs/js/sdk.js";g.async=true;s.parentNode.insertBefore(g,s);g.onload=function(){window.chatwootSDK.run({websiteToken:"LdmfJzftdJGEcFjoTqk8CrSq",baseUrl:BASE_URL})}})(document,"script");'; document.body.append(chat_banner); const root = document.documentElement; - root.style.setProperty("--s-700", "var(--gray-50)"); + root.style.setProperty("--s-700", "var(--gray-500)"); } } @@ -103,5 +107,5 @@ function checkBusinessHours() { let currentTime = new Date(); const istTime = new Date(currentTime.toLocaleString("en-US", { timeZone: "Asia/Kolkata" })); - return istTime.getHours() >= 11 && istTime.getHours() <= 18; + return istTime.getHours() >= 11 && istTime.getHours() < 18; } diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index fb888880f3..e61e0f3b78 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -2229,4 +2229,16 @@ Object.assign(frappe.utils, { } return value; }, + get_installed_apps() { + return frappe.boot.app_data.map((app) => { + return app.app_name; + }); + }, + is_sub_array(big, small) { + let i = 0; + for (let num of big) { + if (num === small[i]) i++; + } + return i === small.length; + }, }); From 4ae1db0d6b7c9370838af5f6262a5e443ec215c8 Mon Sep 17 00:00:00 2001 From: MochaMind Date: Thu, 26 Feb 2026 04:44:41 +0530 Subject: [PATCH 67/70] fix: Swedish translations --- frappe/locale/sv.po | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po index 0b77050332..7ad41225a0 100644 --- a/frappe/locale/sv.po +++ b/frappe/locale/sv.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" "POT-Creation-Date: 2026-02-22 09:42+0000\n" -"PO-Revision-Date: 2026-02-23 22:07\n" +"PO-Revision-Date: 2026-02-25 23:14\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Swedish\n" "MIME-Version: 1.0\n" @@ -2868,7 +2868,7 @@ msgstr "Tilldelning Klar" #. Label of the assignment_days (Table) field in DocType 'Assignment Rule' #: frappe/automation/doctype/assignment_rule/assignment_rule.json msgid "Assignment Days" -msgstr "Automation Dagar" +msgstr "Tilldelning Dagar" #. Name of a DocType #. Label of the assignment_rule (Link) field in DocType 'ToDo' @@ -2876,7 +2876,7 @@ msgstr "Automation Dagar" #: frappe/automation/doctype/assignment_rule/assignment_rule.json #: frappe/desk/doctype/todo/todo.json frappe/workspace_sidebar/automation.json msgid "Assignment Rule" -msgstr "Automation Regel" +msgstr "Tilldelning Regel" #. Name of a DocType #: frappe/automation/doctype/assignment_rule_day/assignment_rule_day.json @@ -2890,13 +2890,13 @@ msgstr "Automation Regel Användare" #: frappe/automation/doctype/assignment_rule/assignment_rule.py:55 msgid "Assignment Rule is not allowed on document type {0}" -msgstr "Automation Regel är ej tillåten på dokument typ {0}" +msgstr "Tilldelning Regel är ej tillåten på dokument typ {0}" #. Label of the assignment_rules_section (Section Break) field in DocType #. 'Assignment Rule' #: frappe/automation/doctype/assignment_rule/assignment_rule.json msgid "Assignment Rules" -msgstr "Automation Regler" +msgstr "Tilldelning Regler" #: frappe/desk/doctype/notification_log/notification_log.py:153 msgid "Assignment Update on {0}" From 431ffa074b9a5a9e8abcc09275fac3786970e9d3 Mon Sep 17 00:00:00 2001 From: MochaMind Date: Thu, 26 Feb 2026 04:44:53 +0530 Subject: [PATCH 68/70] fix: Persian translations --- frappe/locale/fa.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/locale/fa.po b/frappe/locale/fa.po index cd633e0b2d..8862e8e299 100644 --- a/frappe/locale/fa.po +++ b/frappe/locale/fa.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" "POT-Creation-Date: 2026-02-22 09:42+0000\n" -"PO-Revision-Date: 2026-02-23 22:07\n" +"PO-Revision-Date: 2026-02-25 23:14\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Persian\n" "MIME-Version: 1.0\n" @@ -6314,7 +6314,7 @@ msgstr "سفارشی‌سازی" #: frappe/custom/doctype/customize_form/customize_form.js:89 msgid "Customize Child Table" -msgstr "سفارشی کردن جدول فرزند" +msgstr "سفارشی‌سازی جدول فرزند" #: frappe/public/js/frappe/views/dashboard/dashboard_view.js:38 msgid "Customize Dashboard" @@ -6339,7 +6339,7 @@ msgstr "سفارشی‌سازی فرم - {0}" #. Name of a DocType #: frappe/custom/doctype/customize_form_field/customize_form_field.json msgid "Customize Form Field" -msgstr "سفارشی کردن فیلد فرم" +msgstr "سفارشی‌سازی فیلد فرم" #: frappe/public/js/frappe/list/list_view.js:1994 msgctxt "Customize qucik filters of List View" @@ -18808,7 +18808,7 @@ msgstr "" #: frappe/core/doctype/doctype/doctype.py:1699 msgid "Options for Rating field can range from 3 to 10" -msgstr "گزینه‌های فیلد رتبه بندی می‌تواند از 3 تا 10 باشد" +msgstr "گزینه‌های فیلد رتبه‌بندی می‌تواند از 3 تا 10 باشد" #: frappe/custom/doctype/custom_field/custom_field.js:96 msgid "Options for select. Each option on a new line." From f1991ef1270a7e13a485a59937bdaf6f47142df7 Mon Sep 17 00:00:00 2001 From: MochaMind Date: Thu, 26 Feb 2026 04:44:58 +0530 Subject: [PATCH 69/70] fix: Croatian translations --- frappe/locale/hr.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/locale/hr.po b/frappe/locale/hr.po index 9f534aaf36..8851d800e9 100644 --- a/frappe/locale/hr.po +++ b/frappe/locale/hr.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" "POT-Creation-Date: 2026-02-22 09:42+0000\n" -"PO-Revision-Date: 2026-02-23 22:07\n" +"PO-Revision-Date: 2026-02-25 23:14\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Croatian\n" "MIME-Version: 1.0\n" @@ -2870,7 +2870,7 @@ msgstr "Dodjela je Završena" #. Label of the assignment_days (Table) field in DocType 'Assignment Rule' #: frappe/automation/doctype/assignment_rule/assignment_rule.json msgid "Assignment Days" -msgstr "Dani Dodjeljivanja" +msgstr "Dani Dodjele" #. Name of a DocType #. Label of the assignment_rule (Link) field in DocType 'ToDo' From 20f20444f0592d433b949cb07371357cf9918bed Mon Sep 17 00:00:00 2001 From: MochaMind Date: Thu, 26 Feb 2026 04:45:02 +0530 Subject: [PATCH 70/70] fix: Bosnian translations --- frappe/locale/bs.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/locale/bs.po b/frappe/locale/bs.po index c0467055e8..f05ddd2f43 100644 --- a/frappe/locale/bs.po +++ b/frappe/locale/bs.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" "POT-Creation-Date: 2026-02-22 09:42+0000\n" -"PO-Revision-Date: 2026-02-23 22:07\n" +"PO-Revision-Date: 2026-02-25 23:15\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Bosnian\n" "MIME-Version: 1.0\n" @@ -2870,7 +2870,7 @@ msgstr "Dodjela je Završena" #. Label of the assignment_days (Table) field in DocType 'Assignment Rule' #: frappe/automation/doctype/assignment_rule/assignment_rule.json msgid "Assignment Days" -msgstr "Dani Dodjeljivanja" +msgstr "Dani Dodjele" #. Name of a DocType #. Label of the assignment_rule (Link) field in DocType 'ToDo' @@ -2888,7 +2888,7 @@ msgstr "Dan Dodjele Pravila" #. Name of a DocType #: frappe/automation/doctype/assignment_rule_user/assignment_rule_user.json msgid "Assignment Rule User" -msgstr "Korisnik Dodjele Pravila" +msgstr "Korisnik Pravila Dodjele" #: frappe/automation/doctype/assignment_rule/assignment_rule.py:55 msgid "Assignment Rule is not allowed on document type {0}"