From 90feab850cd48687341ff3e605a61cebe6a2ac02 Mon Sep 17 00:00:00 2001 From: Sanskar Soni Date: Tue, 7 Apr 2026 15:19:57 +0530 Subject: [PATCH 1/4] feat: whitelabel msgprint Signed-off-by: Sanskar Soni --- clientside/hooks.py | 3 +- clientside/public/js/clientside.bundle.js | 3 + clientside/public/js/whitelabel.js | 106 ++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 clientside/public/js/clientside.bundle.js create mode 100644 clientside/public/js/whitelabel.js diff --git a/clientside/hooks.py b/clientside/hooks.py index 20c1fa0..3a9bfce 100644 --- a/clientside/hooks.py +++ b/clientside/hooks.py @@ -14,6 +14,7 @@ # include js, css files in header of desk.html # app_include_css = "" app_include_js = [ + "clientside.bundle.js", "assets/clientside/js/check_subscription.js", "/assets/clientside/js/support_widget.js", ] @@ -50,7 +51,7 @@ # "Role": "home_page" # } -after_migrate = ['clientside.api.update_workspaces'] +after_migrate = ["clientside.api.update_workspaces"] # Generators # ---------- diff --git a/clientside/public/js/clientside.bundle.js b/clientside/public/js/clientside.bundle.js new file mode 100644 index 0000000..7d6c766 --- /dev/null +++ b/clientside/public/js/clientside.bundle.js @@ -0,0 +1,3 @@ +import "./check_subscription"; +import "./support_widget"; +import "./whitelabel"; diff --git a/clientside/public/js/whitelabel.js b/clientside/public/js/whitelabel.js new file mode 100644 index 0000000..2c7a107 --- /dev/null +++ b/clientside/public/js/whitelabel.js @@ -0,0 +1,106 @@ +const LINK_MAP = { + "https://docs.erpnext.com//docs/user/manual/en/setting-up/articles/delete-submitted-document": + "https://chat.onehash.ai/hc/onehash-help-center/articles/1701752414-delete-submitted-document", + "https://docs.erpnext.com/docs/v14/user/manual/en/regional/india/generating_e_invoice#what-if-we-generate-e-waybill-before-the-e-invoice": + "https://chat.onehash.ai/hc/onehash-help-center/articles/1701664426-e_invoicing-under-gst#generating-irn", + "https://docs.erpnext.com/docs/user/manual/en/regional/india/gst-setup": + "https://chat.onehash.ai/hc/onehash-help-center/articles/1701753695-gst-setup", +}; + +const DOCS_FALLBACK = "https://chat.onehash.ai/hc/onehash-help-center/en/"; +const HOME_FALLBACK = "https://onehash.ai"; +const GITHUB_FALLBACK = "https://github.com/onehashai"; + +function whitelabelText(str) { + if (typeof str !== "string") return str; + return str + .replace(/\bERPNext\b/gi, "OneHash") + .replace(/\bFrappe\b/gi, "OneHash"); +} + +function whitelabelLink(url) { + if (!url) return url; + + if (LINK_MAP[url]) return LINK_MAP[url]; + + if (/https?:\/\/docs\.(erpnext|frappe)\./i.test(url)) return DOCS_FALLBACK; + + if (/https?:\/\/github\.com\/frappe\//i.test(url)) return GITHUB_FALLBACK; + + if (/https?:\/\/[^/]*(erpnext|frappe)[^/]*/i.test(url)) return HOME_FALLBACK; + + return url; +} + +function whitelabelHTML(html) { + if (typeof html !== "string") return html; + + html = html.replace( + /(href|src)=(["'])([^"']+)\2/gi, + (match, attr, quote, url) => { + return `${attr}=${quote}${whitelabelLink(url)}${quote}`; + }, + ); + + html = html.replace(/(?<=>|^)([^<]+)/g, (match) => whitelabelText(match)); + + return html; +} + +function whitelabelMessage(msg) { + if (typeof msg === "string") { + return whitelabelHTML(msg); + } + if (Array.isArray(msg)) { + return msg.map((item) => { + if (typeof item === "string") { + try { + const parsed = JSON.parse(item); + return JSON.stringify(whitelabelData(parsed)); + } catch { + return whitelabelHTML(item); + } + } + return typeof item === "object" ? whitelabelData(item) : item; + }); + } + return msg; +} + +function whitelabelData(data) { + if (!data) return data; + + if (data.title) { + data.title = whitelabelText(data.title); + } + + if (data.message !== undefined) { + data.message = whitelabelMessage(data.message); + } + + return data; +} + +const _msgprint = frappe.msgprint; + +frappe.msgprint = function (msg, title, is_minimizable) { + if (!msg) return; + + let data; + + if ($.isPlainObject(msg)) { + data = msg; + } else if (typeof msg === "string" && msg.trimStart().startsWith("{")) { + try { + data = JSON.parse(msg); + } catch { + data = { message: msg, title: title }; + } + } else { + data = { message: msg, title: title }; + } + + data = whitelabelData(data); + + _msgprint(data, data.title, is_minimizable); +}; From 76dbd93aaf8164e81c7c6af863634807b2f90c53 Mon Sep 17 00:00:00 2001 From: Sanskar Soni Date: Wed, 8 Apr 2026 09:47:09 +0530 Subject: [PATCH 2/4] fix(whitelabel): fix github link match regex Signed-off-by: Sanskar Soni --- clientside/public/js/whitelabel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clientside/public/js/whitelabel.js b/clientside/public/js/whitelabel.js index 2c7a107..b8c0357 100644 --- a/clientside/public/js/whitelabel.js +++ b/clientside/public/js/whitelabel.js @@ -25,7 +25,8 @@ function whitelabelLink(url) { if (/https?:\/\/docs\.(erpnext|frappe)\./i.test(url)) return DOCS_FALLBACK; - if (/https?:\/\/github\.com\/frappe\//i.test(url)) return GITHUB_FALLBACK; + if (/https?:\/\/github\.com\/(erpnext|frappe)\//i.test(url)) + return GITHUB_FALLBACK; if (/https?:\/\/[^/]*(erpnext|frappe)[^/]*/i.test(url)) return HOME_FALLBACK; From 35e0659eca73dadf0b9835276b4e07c88ff46674 Mon Sep 17 00:00:00 2001 From: Sanskar Soni Date: Wed, 8 Apr 2026 09:48:54 +0530 Subject: [PATCH 3/4] feat(install): whitelabel workspace shortcut links Signed-off-by: Sanskar Soni --- clientside/install.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/clientside/install.py b/clientside/install.py index ce4d5d1..c418634 100644 --- a/clientside/install.py +++ b/clientside/install.py @@ -7,6 +7,7 @@ def after_install(): create_role("OneHash Manager") update_workspace_title() + update_workspace_shortcuts() hide_integrations() update_workspace_shortcut() update_navbar_settings() @@ -56,6 +57,31 @@ def update_workspace_title(): frappe.db.rollback() +def update_workspace_shortcuts(): + workspaces_to_update = frappe.get_all( + "Workspace", + filters=[["Workspace Shortcut", "url", "like", "%frappe%"]], + fields=["name"], + ) + + for workspace in workspaces_to_update: + workspace_doc = frappe.get_doc("Workspace", workspace["name"]) + + shortcuts_to_remove = [ + s + for s in workspace_doc.shortcuts + if s.url + and ( + s.url.startswith("https://frappe") or s.url.startwith("https://erpnext") + ) + ] + for shortcut in shortcuts_to_remove: + workspace_doc.remove(shortcut) + + if len(shortcuts_to_remove): + workspace_doc.save() + + def hide_integrations(): workspaces_to_update = frappe.get_all( "Workspace", From ff1958478e417f5f1b4b9cf6a9a7b0e384158687 Mon Sep 17 00:00:00 2001 From: Sanskar Soni Date: Wed, 8 Apr 2026 10:04:38 +0530 Subject: [PATCH 4/4] fix(install): update workspace shortcuts merge Signed-off-by: Sanskar Soni --- clientside/install.py | 53 +++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/clientside/install.py b/clientside/install.py index c418634..4c4cb96 100644 --- a/clientside/install.py +++ b/clientside/install.py @@ -7,9 +7,8 @@ def after_install(): create_role("OneHash Manager") update_workspace_title() - update_workspace_shortcuts() hide_integrations() - update_workspace_shortcut() + update_workspace_shortcuts() update_navbar_settings() add_custom_fields_to_communication() add_custom_fields_to_email_campaign() @@ -57,31 +56,6 @@ def update_workspace_title(): frappe.db.rollback() -def update_workspace_shortcuts(): - workspaces_to_update = frappe.get_all( - "Workspace", - filters=[["Workspace Shortcut", "url", "like", "%frappe%"]], - fields=["name"], - ) - - for workspace in workspaces_to_update: - workspace_doc = frappe.get_doc("Workspace", workspace["name"]) - - shortcuts_to_remove = [ - s - for s in workspace_doc.shortcuts - if s.url - and ( - s.url.startswith("https://frappe") or s.url.startwith("https://erpnext") - ) - ] - for shortcut in shortcuts_to_remove: - workspace_doc.remove(shortcut) - - if len(shortcuts_to_remove): - workspace_doc.save() - - def hide_integrations(): workspaces_to_update = frappe.get_all( "Workspace", @@ -99,18 +73,27 @@ def hide_integrations(): print("Workspace 'Integrations' not found.") -def update_workspace_shortcut(): - workspace_shortcut_to_update = frappe.get_all( - "Workspace Shortcut", - filters={"label": "Browse Apps"}, - fields=["name", "label", "url"], +def update_workspace_shortcuts(): + workspace_shortcuts = frappe.get_all( + "Workspace Shortcut", fields=["name", "label", "url"] ) - if workspace_shortcut_to_update: - for shortcut in workspace_shortcut_to_update: + + workspace_shortcuts_to_remove = [] + for shortcut in workspace_shortcuts: + if shortcut["url"] and ( + shortcut["url"].startswith("https://frappe") + or shortcut["url"].startwith("https://erpnext") + ): + workspace_shortcuts_to_remove.append(shortcut) + elif shortcut["label"] == "Browse Apps": + workspace_shortcuts_to_remove.append(shortcut) + + if workspace_shortcuts_to_remove: + for shortcut in workspace_shortcuts_to_remove: frappe.delete_doc("Workspace Shortcut", shortcut["name"]) frappe.db.commit() else: - print("No workspace shortcut with label 'Browse Apps' found.") + print("No workspace shortcut to update.") def update_navbar_settings():