diff --git a/frappe/commands/test_commands.py b/frappe/commands/test_commands.py index bd9697d599..f3d9f3d0d9 100644 --- a/frappe/commands/test_commands.py +++ b/frappe/commands/test_commands.py @@ -1116,6 +1116,7 @@ class TestGunicornWorker(IntegrationTestCase): time.sleep(2) execute_in_shell("pgrep gunicorn | xargs -L1 kill -9") + @unittest.skip("Flaky test") def test_gunicorn_ping_sync(self): self.spawn_gunicorn() path = f"http://{self.TEST_SITE}:{self.port}/api/method/ping" @@ -1126,6 +1127,7 @@ class TestGunicornWorker(IntegrationTestCase): path = f"http://{self.TEST_SITE}:{self.port}/api/method/ping" self.assertEqual(requests.get(path).status_code, 200) + @unittest.skip("Flaky test") def test_gunicorn_idle_cpu_usage(self): def get_total_usage(): process = psutil.Process(self.handle.pid) 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/core/doctype/file/file.js b/frappe/core/doctype/file/file.js index f3f1380855..2dd4bb48a2 100644 --- a/frappe/core/doctype/file/file.js +++ b/frappe/core/doctype/file/file.js @@ -43,25 +43,34 @@ frappe.ui.form.on("File", { if (!frappe.utils.can_upload_public_files() && frm.doc.is_private) { frm.set_df_property("is_private", "read_only", 1); } + + if (frm.doc.attached_to_name) { + const field = frm.get_field("attached_to_name"); + field.$input_wrapper + .find(".control-value") + .html(`${frappe.utils.get_form_link(frm.doctype, frm.docname, true)}`); + } }, preview_file: function (frm) { let $preview = ""; let file_extension = frm.doc.file_type.toLowerCase(); + const full_file_url = frm.doc.file_url + "?fid=" + frm.doc.name; + const src_url = frappe.utils.escape_html(full_file_url); - if (frappe.utils.is_image_file(frm.doc.file_url)) { + if (frappe.utils.is_image_file(full_file_url)) { $preview = $(`
{%= frappe.utils.icon("user-check" , "sm", "", "", "text-ink-gray-7 current-color", true)%} diff --git a/frappe/public/js/frappe/ui/sidebar/sidebar.js b/frappe/public/js/frappe/ui/sidebar/sidebar.js index 84f4665ffd..236a94d49e 100644 --- a/frappe/public/js/frappe/ui/sidebar/sidebar.js +++ b/frappe/public/js/frappe/ui/sidebar/sidebar.js @@ -78,9 +78,95 @@ frappe.ui.Sidebar = class Sidebar { } } + setup_promotional_banners() { + if ( + cint(frappe.sys_defaults?.disable_product_suggestion) || + !frappe.user.has_role("System Manager") + ) + return; + + let module = this.all_sidebar_items?.[this.workspace_title]?.["module"] || ""; + if (!module) return; + + this.$promotional_banners = this.wrapper.find(".promotional-banners"); + this.$promotional_banners.empty(); + this.promotional_banners = []; + + this.get_crm_banner(module); + this.get_helpdesk_banner(module); + + this.render_promotional_banners(); + } + + get_crm_banner(module) { + if (module != "CRM") return; + + const icon = + $(` + + + +`); + + const title = __("Switch to Frappe CRM"); + const message = __( + "Sales without complexity, lock-in and per-user costs. Try it for free!" + ); + const link = + "https://frappe.io/crm?utm_source=crm-sidebar&utm_medium=sidebar&utm_campaign=frappe-ad"; + + this.promotional_banners.push({ title, message, link, icon }); + } + + get_helpdesk_banner(module) { + if (module != "Support") return; + + const icon = + $(` + + + +`); + + const title = __("Switch to Helpdesk"); + const message = __( + "Support without complexity, lock-in and per-user costs. Try it for free!" + ); + const link = + "https://frappe.io/helpdesk?utm_source=support-sidebar&utm_medium=sidebar&utm_campaign=frappe-ad"; + + this.promotional_banners.push({ title, message, link, icon }); + } + + render_promotional_banners() { + let me = this; + + if (this.promotional_banners.length === 0) { + this.$promotional_banners.hide(); + return; + } + + this.$promotional_banners.show(); + + this.promotional_banners.forEach((banner) => { + let banner_html = $(` + + ${banner.title} + + `); + + banner_html.prepend(banner.icon); + me.$promotional_banners.append(banner_html); + }); + } + remove_onboarding_wrapper() { this.$onboarding.empty(); this.wrapper.find(".onboarding-sidebar").removeClass("hidden"); + + if (!this.sidebar_data?.module_onboarding) { + this.wrapper.find(".onboarding-sidebar").addClass("hidden"); + } } setup_onboarding() { @@ -170,6 +256,7 @@ frappe.ui.Sidebar = class Sidebar { this.sidebar_header = new frappe.ui.SidebarHeader(this); this.make_sidebar(); this.add_sidebar_cards(); + this.setup_promotional_banners(); this.setup_onboarding(); this.wrapper.find(".onboarding-sidebar").click(() => { diff --git a/frappe/public/js/frappe/ui/user_onboarding/OnboardingPanel.vue b/frappe/public/js/frappe/ui/user_onboarding/OnboardingPanel.vue index 17dde86cc6..9ee883cf31 100644 --- a/frappe/public/js/frappe/ui/user_onboarding/OnboardingPanel.vue +++ b/frappe/public/js/frappe/ui/user_onboarding/OnboardingPanel.vue @@ -235,7 +235,7 @@ function markReset(step) {