From c2c858f70e8aabf5c23b8922130b98d7d4e22fb7 Mon Sep 17 00:00:00 2001 From: shadrak gurupnor Date: Thu, 24 Feb 2022 09:49:43 +0530 Subject: [PATCH 001/251] fix: clean up logs job was broken --- frappe/core/doctype/activity_log/activity_log.py | 3 ++- frappe/core/doctype/log_settings/log_settings.py | 3 ++- frappe/email/queue.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/activity_log/activity_log.py b/frappe/core/doctype/activity_log/activity_log.py index 69565a2c2a..92a23dcc04 100644 --- a/frappe/core/doctype/activity_log/activity_log.py +++ b/frappe/core/doctype/activity_log/activity_log.py @@ -48,6 +48,7 @@ def clear_activity_logs(days=None): if not days: days = 90 doctype = DocType("Activity Log") + duration = (Now() - Interval(days=days)) frappe.db.delete(doctype, filters=( - doctype.creation < PseudoColumn(f"({Now() - Interval(days=days)})") + doctype.creation < duration )) \ No newline at end of file diff --git a/frappe/core/doctype/log_settings/log_settings.py b/frappe/core/doctype/log_settings/log_settings.py index 5c9bc6c265..8dcf5f4ade 100644 --- a/frappe/core/doctype/log_settings/log_settings.py +++ b/frappe/core/doctype/log_settings/log_settings.py @@ -18,8 +18,9 @@ class LogSettings(Document): def clear_error_logs(self): table = DocType("Error Log") + duration = (Now() - Interval(days=self.clear_error_log_after)) frappe.db.delete(table, filters=( - table.creation < PseudoColumn(f"({Now() - Interval(days=self.clear_error_log_after)})") + table.creation < duration )) def clear_activity_logs(self): diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 16e3fecf48..79c9aa7e03 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -170,7 +170,7 @@ def clear_outbox(days=None): days=31 email_queues = frappe.db.sql_list("""SELECT `name` FROM `tabEmail Queue` - WHERE `priority`=0 AND `modified` < (NOW() - INTERVAL '{0}' DAY)""".format(days)) + WHERE `modified` < (NOW() - INTERVAL '{0}' DAY)""".format(days)) if email_queues: frappe.db.delete("Email Queue", {"name": ("in", email_queues)}) From 75583bf692f84c4b74ce5088c1191602c044ff0c Mon Sep 17 00:00:00 2001 From: shadrak gurupnor Date: Thu, 24 Feb 2022 18:02:15 +0530 Subject: [PATCH 002/251] fix: removed redundant pieces & rewrote the query with qb --- frappe/core/doctype/activity_log/activity_log.py | 3 +-- frappe/core/doctype/log_settings/log_settings.py | 4 +--- frappe/email/queue.py | 11 +++++++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/frappe/core/doctype/activity_log/activity_log.py b/frappe/core/doctype/activity_log/activity_log.py index 92a23dcc04..0a02b45d32 100644 --- a/frappe/core/doctype/activity_log/activity_log.py +++ b/frappe/core/doctype/activity_log/activity_log.py @@ -48,7 +48,6 @@ def clear_activity_logs(days=None): if not days: days = 90 doctype = DocType("Activity Log") - duration = (Now() - Interval(days=days)) frappe.db.delete(doctype, filters=( - doctype.creation < duration + doctype.creation < (Now() - Interval(days=days)) )) \ No newline at end of file diff --git a/frappe/core/doctype/log_settings/log_settings.py b/frappe/core/doctype/log_settings/log_settings.py index 8dcf5f4ade..dec33070c0 100644 --- a/frappe/core/doctype/log_settings/log_settings.py +++ b/frappe/core/doctype/log_settings/log_settings.py @@ -7,7 +7,6 @@ from frappe import _ from frappe.model.document import Document from frappe.query_builder import DocType, Interval from frappe.query_builder.functions import Now -from pypika.terms import PseudoColumn class LogSettings(Document): @@ -18,9 +17,8 @@ class LogSettings(Document): def clear_error_logs(self): table = DocType("Error Log") - duration = (Now() - Interval(days=self.clear_error_log_after)) frappe.db.delete(table, filters=( - table.creation < duration + table.creation < (Now() - Interval(days=self.clear_error_log_after)) )) def clear_activity_logs(self): diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 79c9aa7e03..629b23b601 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -5,6 +5,8 @@ import frappe from frappe import msgprint, _ from frappe.utils.verified_command import get_signed_params, verify_request from frappe.utils import get_url, now_datetime, cint +from frappe.query_builder import DocType, Interval +from frappe.query_builder.functions import Now def get_emails_sent_this_month(email_account=None): """Get count of emails sent from a specific email account. @@ -169,8 +171,13 @@ def clear_outbox(days=None): if not days: days=31 - email_queues = frappe.db.sql_list("""SELECT `name` FROM `tabEmail Queue` - WHERE `modified` < (NOW() - INTERVAL '{0}' DAY)""".format(days)) + email_queue = DocType("Email Queue") + queues = (frappe.qb.from_(email_queue) + .select(email_queue.name) + .where(email_queue.modified < (Now() - Interval(days=days))) + .run(as_dict=True)) + + email_queues = [queue.name for queue in queues] if email_queues: frappe.db.delete("Email Queue", {"name": ("in", email_queues)}) From 62eca433d7816e570bdfc3fe4eb6dad245f963de Mon Sep 17 00:00:00 2001 From: shadrak gurupnor Date: Sat, 26 Feb 2022 11:05:52 +0530 Subject: [PATCH 003/251] fix: added test cases for log settings --- .../doctype/log_settings/test_log_settings.py | 129 +++++++++++++++++- 1 file changed, 126 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/log_settings/test_log_settings.py b/frappe/core/doctype/log_settings/test_log_settings.py index 40287948fd..f3021c3e1a 100644 --- a/frappe/core/doctype/log_settings/test_log_settings.py +++ b/frappe/core/doctype/log_settings/test_log_settings.py @@ -1,8 +1,131 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies and Contributors +# Copyright (c) 2022, Frappe Technologies and Contributors # License: MIT. See LICENSE -# import frappe +import frappe import unittest +current = frappe.utils.now_datetime() +past = frappe.utils.add_to_date(current, days=-4) class TestLogSettings(unittest.TestCase): - pass + @classmethod + def setUpClass(cls): + fieldnames = ['clear_error_log_after', 'clear_activity_log_after', 'clear_email_queue_after'] + for fieldname in fieldnames: + frappe.set_value("Log Settings", None, fieldname, 1) + + @classmethod + def tearDownClass(cls): + if frappe.db.exists({"doctype": "Activity Log", "subject": "Test subject"}): + activity_logs = frappe.get_all("Activity Log", filters=dict(subject='Test subject'), pluck='name') + for log in activity_logs: + frappe.db.delete("Activity Log", log) + frappe.db.commit() + + if frappe.db.exists({"doctype": "Email Queue", "expose_recipients": "test@receiver.com"}): + email_queues = frappe.get_all("Email Queue", filters=dict(expose_recipients='test@receiver.com'), pluck='name') + for queue in email_queues: + frappe.db.delete("Email Queue", queue) + frappe.db.commit() + + if frappe.db.exists({"doctype": "Error Log", "method": "test_method"}): + error_logs = frappe.get_all("Error Log", filters=dict(method='test_method'), pluck='name') + for log in error_logs: + frappe.db.delete("Error Log", log) + frappe.db.commit() + + def test_create_activity_logs(self): + doc1 = frappe.get_doc({ + "doctype": "Activity Log", + "subject": "Test subject", + "full_name": "test user1", + }) + doc1.insert(ignore_permissions=True) + + #creation can't be set while inserting new_doc + frappe.db.set_value("Activity Log", doc1.name, "creation", past) + + doc2 = frappe.get_doc({ + "doctype": "Activity Log", + "subject": "Test subject", + "full_name": "test user2", + "creation": current + }) + doc2.insert(ignore_permissions=True) + + activity_logs = frappe.get_all("Activity Log", filters=dict(subject='Test subject'), pluck='name') + + self.assertEqual(len(activity_logs), 2) + + def test_create_error_logs(self): + traceback = """ + Traceback (most recent call last): + File "apps/frappe/frappe/email/doctype/email_account/email_account.py", line 489, in get_inbound_mails + messages = email_server.get_messages() + File "apps/frappe/frappe/email/receive.py", line 166, in get_messages + if self.has_login_limit_exceeded(e): + File "apps/frappe/frappe/email/receive.py", line 315, in has_login_limit_exceeded + return "-ERR Exceeded the login limit" in strip(cstr(e.message)) + AttributeError: 'AttributeError' object has no attribute 'message' + """ + doc1 = frappe.get_doc({ + "doctype": "Error Log", + "method": "test_method", + "error": traceback, + "creation": past + }) + doc1.insert(ignore_permissions=True) + + frappe.db.set_value("Error Log", doc1.name, "creation", past) + + doc2 = frappe.get_doc({ + "doctype": "Error Log", + "method": "test_method", + "error": traceback, + "creation": current + }) + doc2.insert(ignore_permissions=True) + + error_logs = frappe.get_all("Error Log", filters=dict(method='test_method'), pluck='name') + self.assertEqual(len(error_logs), 2) + + def test_create_email_queue(self): + doc1 = frappe.get_doc({ + "doctype": "Email Queue", + "sender": "test1@example.com", + "message": "This is a test email1", + "priority": 1, + "expose_recipients": "test@receiver.com", + }) + doc1.insert(ignore_permissions=True) + + frappe.db.set_value("Email Queue", doc1.name, "creation", past) + frappe.db.set_value("Email Queue", doc1.name, "modified", past, update_modified=False) + + doc2 = frappe.get_doc({ + "doctype": "Email Queue", + "sender": "test2@example.com", + "message": "This is a test email2", + "priority": 1, + "expose_recipients": "test@receiver.com", + "creation": current + }) + doc2.insert(ignore_permissions=True) + + email_queues = frappe.get_all("Email Queue", filters=dict(expose_recipients="test@receiver.com"), pluck='name') + + self.assertEqual(len(email_queues), 2) + + def test_delete_logs(self): + from frappe.core.doctype.log_settings.log_settings import run_log_clean_up + + run_log_clean_up() + + activity_logs = frappe.get_all("Activity Log", filters=dict(subject='Test subject'), pluck='name') + self.assertEqual(len(activity_logs), 1) + + error_logs = frappe.get_all("Error Log", filters=dict(method='test_method'), pluck='name') + self.assertEqual(len(error_logs), 1) + + email_queues = frappe.get_all("Email Queue", filters=dict(expose_recipients='test@receiver.com'), pluck='name') + self.assertEqual(len(email_queues), 1) + From 05a658c86ed243cd4c61a4b0b3fabc38c349de3d Mon Sep 17 00:00:00 2001 From: shadrak gurupnor Date: Sat, 26 Feb 2022 11:08:36 +0530 Subject: [PATCH 004/251] chore: fix linter issues --- frappe/core/doctype/log_settings/test_log_settings.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/frappe/core/doctype/log_settings/test_log_settings.py b/frappe/core/doctype/log_settings/test_log_settings.py index f3021c3e1a..60ee75e5dc 100644 --- a/frappe/core/doctype/log_settings/test_log_settings.py +++ b/frappe/core/doctype/log_settings/test_log_settings.py @@ -19,19 +19,16 @@ class TestLogSettings(unittest.TestCase): activity_logs = frappe.get_all("Activity Log", filters=dict(subject='Test subject'), pluck='name') for log in activity_logs: frappe.db.delete("Activity Log", log) - frappe.db.commit() if frappe.db.exists({"doctype": "Email Queue", "expose_recipients": "test@receiver.com"}): email_queues = frappe.get_all("Email Queue", filters=dict(expose_recipients='test@receiver.com'), pluck='name') for queue in email_queues: frappe.db.delete("Email Queue", queue) - frappe.db.commit() if frappe.db.exists({"doctype": "Error Log", "method": "test_method"}): error_logs = frappe.get_all("Error Log", filters=dict(method='test_method'), pluck='name') for log in error_logs: frappe.db.delete("Error Log", log) - frappe.db.commit() def test_create_activity_logs(self): doc1 = frappe.get_doc({ From 91b220c37c6fcd84e91285beff515aca8935f3c2 Mon Sep 17 00:00:00 2001 From: shadrak gurupnor Date: Sat, 26 Feb 2022 12:18:08 +0530 Subject: [PATCH 005/251] fix: added proper messages --- frappe/custom/doctype/customize_form/customize_form.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/custom/doctype/customize_form/customize_form.js b/frappe/custom/doctype/customize_form/customize_form.js index 4862185b99..75e3f8a274 100644 --- a/frappe/custom/doctype/customize_form/customize_form.js +++ b/frappe/custom/doctype/customize_form/customize_form.js @@ -134,7 +134,7 @@ frappe.ui.form.on("Customize Form", { ); frm.add_custom_button( - __("Reset to defaults"), + __("Reset Property Setters"), function() { frappe.customize_form.confirm( __("Remove all customizations?"), @@ -315,9 +315,9 @@ frappe.customize_form.confirm = function(msg, frm) { if (!frm.doc.doc_type) return; var d = new frappe.ui.Dialog({ - title: 'Reset To Defaults', + title: 'Reset Property Setters', fields: [ - {fieldtype:"HTML", options:__("All customizations will be removed. Please confirm.")}, + {fieldtype:"HTML", options:__("All property setters will be removed. Please confirm.")}, ], primary_action: function() { return frm.call({ @@ -328,7 +328,7 @@ frappe.customize_form.confirm = function(msg, frm) { frappe.msgprint(r.exc); } else { d.hide(); - frappe.show_alert({message:__('Customizations Reset'), indicator:'green'}); + frappe.show_alert({message:__('Property Setters Reset'), indicator:'green'}); frappe.customize_form.clear_locals_and_refresh(frm); } } From d76eca36fe3e2b87a412767b7eb345fcae774d95 Mon Sep 17 00:00:00 2001 From: shadrak gurupnor Date: Mon, 28 Feb 2022 13:52:15 +0530 Subject: [PATCH 006/251] fix: remove custom fields as well on reset to default --- .../custom/doctype/customize_form/customize_form.js | 8 ++++---- .../custom/doctype/customize_form/customize_form.py | 11 ++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/frappe/custom/doctype/customize_form/customize_form.js b/frappe/custom/doctype/customize_form/customize_form.js index 75e3f8a274..4862185b99 100644 --- a/frappe/custom/doctype/customize_form/customize_form.js +++ b/frappe/custom/doctype/customize_form/customize_form.js @@ -134,7 +134,7 @@ frappe.ui.form.on("Customize Form", { ); frm.add_custom_button( - __("Reset Property Setters"), + __("Reset to defaults"), function() { frappe.customize_form.confirm( __("Remove all customizations?"), @@ -315,9 +315,9 @@ frappe.customize_form.confirm = function(msg, frm) { if (!frm.doc.doc_type) return; var d = new frappe.ui.Dialog({ - title: 'Reset Property Setters', + title: 'Reset To Defaults', fields: [ - {fieldtype:"HTML", options:__("All property setters will be removed. Please confirm.")}, + {fieldtype:"HTML", options:__("All customizations will be removed. Please confirm.")}, ], primary_action: function() { return frm.call({ @@ -328,7 +328,7 @@ frappe.customize_form.confirm = function(msg, frm) { frappe.msgprint(r.exc); } else { d.hide(); - frappe.show_alert({message:__('Property Setters Reset'), indicator:'green'}); + frappe.show_alert({message:__('Customizations Reset'), indicator:'green'}); frappe.customize_form.clear_locals_and_refresh(frm); } } diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index 92a540447f..13474fdbdf 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -487,12 +487,21 @@ def reset_customization(doctype): setters = frappe.get_all("Property Setter", filters={ 'doc_type': doctype, 'field_name': ['!=', 'naming_series'], - 'property': ['!=', 'options'] + 'property': ['!=', 'options'], + 'owner': ['!=', 'Administrator'] }, pluck='name') for setter in setters: frappe.delete_doc("Property Setter", setter) + custom_fields = frappe.get_all("Custom Field", filters={ + 'dt': doctype, + 'owner': ['!=', 'Administrator'] + }, pluck='name') + + for field in custom_fields: + frappe.delete_doc("Custom Field", field) + frappe.clear_cache(doctype=doctype) doctype_properties = { From 487cb39416d8662d42e9755eacce3696d5d154df Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 28 Feb 2022 16:14:24 +0530 Subject: [PATCH 007/251] feat: discussions redesign --- frappe/templates/discussions/button.html | 5 +- frappe/templates/discussions/discussions.js | 28 +--- .../discussions/discussions_section.html | 37 ++--- frappe/templates/discussions/reply_card.html | 9 +- .../templates/discussions/reply_section.html | 50 ++++--- frappe/templates/discussions/search.html | 11 +- frappe/templates/discussions/sidebar.html | 29 ++-- frappe/templates/styles/discussion_style.css | 130 ++++++++++++------ 8 files changed, 169 insertions(+), 130 deletions(-) diff --git a/frappe/templates/discussions/button.html b/frappe/templates/discussions/button.html index 8e61d2412f..746227aa0b 100644 --- a/frappe/templates/discussions/button.html +++ b/frappe/templates/discussions/button.html @@ -1,9 +1,6 @@ {% if frappe.session.user != "Guest" and (condition is not defined or (condition is defined and condition )) %} - + {{ _(cta_title) }} - - {% endif %} diff --git a/frappe/templates/discussions/discussions.js b/frappe/templates/discussions/discussions.js index 19c0f89a49..f1fc568acf 100644 --- a/frappe/templates/discussions/discussions.js +++ b/frappe/templates/discussions/discussions.js @@ -4,8 +4,6 @@ frappe.ready(() => { add_color_to_avatars(); - expand_first_discussion(); - $(".search-field").keyup((e) => { search_topic(e); }); @@ -14,11 +12,11 @@ frappe.ready(() => { show_new_topic_modal(e); }); - $("#login-from-discussion").click((e) => { + $(".login-from-discussion").click((e) => { login_from_discussion(e); }); - $(".sidebar-topic").click((e) => { + $(".sidebar-parent").click((e) => { if ($(e.currentTarget).attr("aria-expanded") == "true") { e.stopPropagation(); } @@ -50,13 +48,11 @@ frappe.ready(() => { clear_comment_box(); }); - if ($(document).width() <= 550) { - $(document).on("click", ".sidebar-parent", () => { - hide_sidebar(); - }); - } + $(document).on("click", ".sidebar-parent", () => { + hide_sidebar(); + }); - $(document).on("click", ".back", (e) => { + $(document).on("click", ".back-button", (e) => { back_to_sidebar(e); }); @@ -97,8 +93,7 @@ const publish_message = (data) => { if ($(`.discussion-on-page[data-topic=${topic.name}]`).length) { post_message_cleanup(); data.template = style_avatar_frame(data.template); - $('
' + data.template) - .insertBefore(`.discussion-on-page[data-topic=${topic.name}] .discussion-form`); + $(data.template).insertBefore(`.discussion-on-page[data-topic=${topic.name}] .discussion-form`); } else if (!first_topic && !single_thread && document_match_found) { post_message_cleanup(); @@ -141,15 +136,6 @@ const update_reply_count = (topic) => { $(`[data-target='#t${topic}']`).find(".reply-count").text(reply_count); }; -const expand_first_discussion = () => { - if ($(document).width() > 550) { - $($(".discussions-parent .collapse")[0]).addClass("show"); - $($(".discussions-sidebar [data-toggle='collapse']")[0]).attr("aria-expanded", true); - } else { - $("#discussion-group").addClass("hide"); - } -}; - const search_topic = (e) => { let input = $(e.currentTarget).val(); diff --git a/frappe/templates/discussions/discussions_section.html b/frappe/templates/discussions/discussions_section.html index 07c229595b..e8572cc802 100644 --- a/frappe/templates/discussions/discussions_section.html +++ b/frappe/templates/discussions/discussions_section.html @@ -9,17 +9,16 @@
{{ _(title) }} + {% include "frappe/templates/discussions/search.html" %} {% if topics and not single_thread %} {% include "frappe/templates/discussions/button.html" %} {% endif %}
-
+
{% if topics and not single_thread %}
- {% include "frappe/templates/discussions/search.html" %} {% for topic in topics %} {% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name})%} @@ -27,7 +26,7 @@ {% endfor %}
-
+
{% for topic in topics %} {% include "frappe/templates/discussions/reply_section.html" %} {% endfor %} @@ -38,19 +37,25 @@ {% include "frappe/templates/discussions/reply_section.html" %} {% else %} -
- -
{{ empty_state_title }}
-
{{ empty_state_subtitle }}
- {% if frappe.session.user == "Guest" %} -
{{ _("Login") }}
- {% elif condition is defined and not condition %} -
- {{ button_name }} +
+
+ +
+
+
{{ empty_state_title }}
+
{{ empty_state_subtitle }}
+
+
+ {% if frappe.session.user == "Guest" %} + + {% elif condition is defined and not condition %} + + {% else %} + {% include "frappe/templates/discussions/button.html" %} + {% endif %}
- {% else %} - {% include "frappe/templates/discussions/button.html" %} - {% endif %}
{% endif %}
diff --git a/frappe/templates/discussions/reply_card.html b/frappe/templates/discussions/reply_card.html index 5ff5261472..8fd1ad597e 100644 --- a/frappe/templates/discussions/reply_card.html +++ b/frappe/templates/discussions/reply_card.html @@ -1,14 +1,13 @@ {% from "frappe/templates/includes/avatar_macro.html" import avatar %}
{% set member = frappe.db.get_value("User", reply.owner, ["name", "full_name", "username"], as_dict=True) %} -
- {% if loop.index == 1 or single_thread %} +
{{ avatar(reply.owner) }} - {% endif %} - + {{ member.full_name }} -
{{ frappe.utils.pretty_date(reply.creation) }}
+
{{ frappe.utils.pretty_date(reply.creation) }}
{{ frappe.utils.md_to_html(reply.reply) }}
diff --git a/frappe/templates/discussions/reply_section.html b/frappe/templates/discussions/reply_section.html index b269883ba0..7e424c5bc6 100644 --- a/frappe/templates/discussions/reply_section.html +++ b/frappe/templates/discussions/reply_section.html @@ -5,39 +5,47 @@ {% endif %} -
- {% if not single_thread %} -
- {{ _("Back") }} -
- {% endif %} +
+ {% if not single_thread %} +
+ + + +
+ {% endif %} - {% if topic and topic.title %} -
{{ topic.title }}
- {% endif %} + {% if topic and topic.title %} +
{{ topic.title }}
+ {% endif %} +
{% for reply in replies %} {% include "frappe/templates/discussions/reply_card.html" %} - - {% if loop.index != replies | length %} -
- {% endif %} {% endfor %} {% if frappe.session.user == "Guest" or (condition is defined and not condition) %} -
- {{ _("Want to join the discussion?") }} - {% if frappe.session.user == "Guest" %} -
{{ _("Login") }}
- {% elif not condition %} -
{{ button_name }} +
+
+ +
+
+
{{ _("Want to discuss?") }}
+
{{ _("Post it here, our mentors will help you out.") }}
+
+
+ {% if frappe.session.user == "Guest" %} + + {% elif condition is defined and not condition %} + + {% endif %}
- {% endif %}
{% else %} {% include "frappe/templates/discussions/comment_box.html" %} {% endif %} -
diff --git a/frappe/templates/discussions/search.html b/frappe/templates/discussions/search.html index 800f2962fd..371c5dce9c 100644 --- a/frappe/templates/discussions/search.html +++ b/frappe/templates/discussions/search.html @@ -1,9 +1,2 @@ -
-
-
- -
-
-
+ diff --git a/frappe/templates/discussions/sidebar.html b/frappe/templates/discussions/sidebar.html index 14d38c86a5..b4da8c3332 100644 --- a/frappe/templates/discussions/sidebar.html +++ b/frappe/templates/discussions/sidebar.html @@ -1,19 +1,24 @@ -