From b4c4dbb418ac98b3d4d581530c37fecdae787fa8 Mon Sep 17 00:00:00 2001 From: Nihantra Patel Date: Mon, 10 Jun 2024 16:48:19 +0530 Subject: [PATCH 001/176] fix: redirect report builder from workspace --- frappe/desk/doctype/workspace/workspace.py | 4 ++++ frappe/desk/doctype/workspace_link/workspace_link.json | 10 +++++++++- frappe/desk/doctype/workspace_link/workspace_link.py | 1 + frappe/public/js/frappe/utils/utils.js | 6 +++--- frappe/public/js/frappe/widgets/links_widget.js | 1 + 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/frappe/desk/doctype/workspace/workspace.py b/frappe/desk/doctype/workspace/workspace.py index 273de542aa..d0a2979a9c 100644 --- a/frappe/desk/doctype/workspace/workspace.py +++ b/frappe/desk/doctype/workspace/workspace.py @@ -80,6 +80,10 @@ class Workspace(Document): except Exception: frappe.throw(_("Content data shoud be a list")) + for d in self.get('links'): + if d.link_type == "Report" and d.is_query_report != 1: + d.report_ref_doctype = frappe.get_value("Report", d.link_to, 'ref_doctype') + def clear_cache(self): super().clear_cache() if self.for_user: diff --git a/frappe/desk/doctype/workspace_link/workspace_link.json b/frappe/desk/doctype/workspace_link/workspace_link.json index e11f606b0e..34575d21e5 100644 --- a/frappe/desk/doctype/workspace_link/workspace_link.json +++ b/frappe/desk/doctype/workspace_link/workspace_link.json @@ -13,6 +13,7 @@ "link_details_section", "link_type", "link_to", + "report_ref_doctype", "column_break_7", "dependencies", "only_for", @@ -116,12 +117,19 @@ "ignore_xss_filter": 1, "label": "Description", "max_height": "7rem" + }, + { + "fieldname": "report_ref_doctype", + "fieldtype": "Link", + "label": "Report Ref DocType", + "options": "DocType", + "read_only": 1 } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-03-23 16:04:06.025772", + "modified": "2024-06-10 16:04:00.746903", "modified_by": "Administrator", "module": "Desk", "name": "Workspace Link", diff --git a/frappe/desk/doctype/workspace_link/workspace_link.py b/frappe/desk/doctype/workspace_link/workspace_link.py index 03da7abe47..d3f8b68965 100644 --- a/frappe/desk/doctype/workspace_link/workspace_link.py +++ b/frappe/desk/doctype/workspace_link/workspace_link.py @@ -28,6 +28,7 @@ class WorkspaceLink(Document): parent: DF.Data parentfield: DF.Data parenttype: DF.Data + report_ref_doctype: DF.Link | None type: DF.Literal["Link", "Card Break"] # end: auto-generated types diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index f015ad577f..bb0e6db565 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1299,10 +1299,10 @@ Object.assign(frappe.utils, { } else if (type === "report") { if (item.is_query_report) { route = "query-report/" + item.name; - } else if (!item.doctype) { - route = "report/" + item.name; + } else if (!item.is_query_report && item.report_ref_doctype) { + route = frappe.router.slug(item.report_ref_doctype) + "/view/report/" + item.name; } else { - route = frappe.router.slug(item.doctype) + "/view/report/" + item.name; + route = "/report/" + item.name; } } else if (type === "page") { route = item.name; diff --git a/frappe/public/js/frappe/widgets/links_widget.js b/frappe/public/js/frappe/widgets/links_widget.js index b83cf04954..d0b5513f11 100644 --- a/frappe/public/js/frappe/widgets/links_widget.js +++ b/frappe/public/js/frappe/widgets/links_widget.js @@ -92,6 +92,7 @@ export default class LinksWidget extends Widget { type: item.link_type, doctype: item.doctype, is_query_report: item.is_query_report, + report_ref_doctype: item.report_ref_doctype, }; if (item.link_type.toLowerCase() == "report" && !item.is_query_report) { From 0de30c897d932b7956501d73aa9d0a420566ecba Mon Sep 17 00:00:00 2001 From: Nihantra Patel Date: Mon, 10 Jun 2024 16:57:26 +0530 Subject: [PATCH 002/176] fix: redirect report builder from workspace --- frappe/public/js/frappe/utils/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index bb0e6db565..6eb1f347a4 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1300,7 +1300,8 @@ Object.assign(frappe.utils, { if (item.is_query_report) { route = "query-report/" + item.name; } else if (!item.is_query_report && item.report_ref_doctype) { - route = frappe.router.slug(item.report_ref_doctype) + "/view/report/" + item.name; + route = + frappe.router.slug(item.report_ref_doctype) + "/view/report/" + item.name; } else { route = "/report/" + item.name; } From 533f23534313ad32f1f68b1618f67396c1e86267 Mon Sep 17 00:00:00 2001 From: Nihantra Patel Date: Mon, 10 Jun 2024 17:00:02 +0530 Subject: [PATCH 003/176] fix: redirect report builder from workspace --- frappe/desk/doctype/workspace/workspace.py | 4 ++-- frappe/public/js/frappe/utils/utils.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/desk/doctype/workspace/workspace.py b/frappe/desk/doctype/workspace/workspace.py index d0a2979a9c..1ea99d33f0 100644 --- a/frappe/desk/doctype/workspace/workspace.py +++ b/frappe/desk/doctype/workspace/workspace.py @@ -80,9 +80,9 @@ class Workspace(Document): except Exception: frappe.throw(_("Content data shoud be a list")) - for d in self.get('links'): + for d in self.get("links"): if d.link_type == "Report" and d.is_query_report != 1: - d.report_ref_doctype = frappe.get_value("Report", d.link_to, 'ref_doctype') + d.report_ref_doctype = frappe.get_value("Report", d.link_to, "ref_doctype") def clear_cache(self): super().clear_cache() diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 6eb1f347a4..d84607a045 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1301,7 +1301,7 @@ Object.assign(frappe.utils, { route = "query-report/" + item.name; } else if (!item.is_query_report && item.report_ref_doctype) { route = - frappe.router.slug(item.report_ref_doctype) + "/view/report/" + item.name; + frappe.router.slug(item.report_ref_doctype) + "/view/report/" + item.name; } else { route = "/report/" + item.name; } From 017b89ec1ab37aade2aa52b86807b15ccb942442 Mon Sep 17 00:00:00 2001 From: Nihantra Patel Date: Mon, 10 Jun 2024 17:01:53 +0530 Subject: [PATCH 004/176] fix: redirect report builder from workspace --- frappe/public/js/frappe/utils/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index d84607a045..a5bf51cb76 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1300,7 +1300,7 @@ Object.assign(frappe.utils, { if (item.is_query_report) { route = "query-report/" + item.name; } else if (!item.is_query_report && item.report_ref_doctype) { - route = + route = frappe.router.slug(item.report_ref_doctype) + "/view/report/" + item.name; } else { route = "/report/" + item.name; From c01eb68b8326f8b4825c0b4a4a147fbc17b37a29 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 10 Jun 2024 18:22:21 +0530 Subject: [PATCH 005/176] feat: add `Frappe Mail` to Service options --- frappe/email/doctype/email_account/email_account.json | 4 ++-- frappe/email/doctype/email_account/email_account.py | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index 5ddaed911d..c496bb34da 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -159,7 +159,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "Service", - "options": "\nGMail\nSendgrid\nSparkPost\nYahoo Mail\nOutlook.com\nYandex.Mail" + "options": "\nFrappe Mail\nGMail\nSendgrid\nSparkPost\nYahoo Mail\nOutlook.com\nYandex.Mail" }, { "fieldname": "mailbox_settings", @@ -637,7 +637,7 @@ "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-04-17 14:46:38.836631", + "modified": "2024-06-10 18:18:08.403133", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index f554235028..3d226c31ed 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -96,13 +96,7 @@ class EmailAccount(Document): send_notification_to: DF.SmallText | None send_unsubscribe_message: DF.Check service: DF.Literal[ - "", - "GMail", - "Sendgrid", - "SparkPost", - "Yahoo Mail", - "Outlook.com", - "Yandex.Mail", + "", "Frappe Mail", "GMail", "Sendgrid", "SparkPost", "Yahoo Mail", "Outlook.com", "Yandex.Mail" ] signature: DF.TextEditor | None smtp_port: DF.Data | None From 37d8e2bb366c8a9c1f349d8cc1fbec99727b1c6f Mon Sep 17 00:00:00 2001 From: David Date: Tue, 11 Jun 2024 19:34:20 +0200 Subject: [PATCH 006/176] perf: lazy load svg sprictes on websites --- frappe/hooks.py | 5 ++++- frappe/templates/base.html | 12 ++++++++++-- .../doctype/website_settings/website_settings.py | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index d29f2167a9..7a97b3ece8 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -43,8 +43,11 @@ doctype_js = { } web_include_js = ["website_script.js"] - web_include_css = [] +web_include_icons = [ + "frappe/icons/timeless/icons.svg", + "frappe/icons/espresso/icons.svg", +] email_css = ["email.bundle.css"] diff --git a/frappe/templates/base.html b/frappe/templates/base.html index 2c992c082f..375f80e8c2 100644 --- a/frappe/templates/base.html +++ b/frappe/templates/base.html @@ -44,6 +44,7 @@ - {% include "public/icons/timeless/icons.svg" %} - {% include "public/icons/espresso/icons.svg" %} {%- block banner -%} {% include "templates/includes/banner_extension.html" ignore missing %} @@ -90,10 +89,19 @@ {% block base_scripts %} + {{ include_script('frappe-web.bundle.js') }} {% endblock %} diff --git a/frappe/website/doctype/website_settings/website_settings.py b/frappe/website/doctype/website_settings/website_settings.py index 567c56f1d6..695c37ee3f 100644 --- a/frappe/website/doctype/website_settings/website_settings.py +++ b/frappe/website/doctype/website_settings/website_settings.py @@ -229,8 +229,8 @@ def get_website_settings(context=None): context.encoded_title = quote(encode(context.title or ""), "") context.web_include_js = hooks.web_include_js or [] - context.web_include_css = hooks.web_include_css or [] + context.web_include_icons = hooks.web_include_icons or [] via_hooks = hooks.website_context or [] for key in via_hooks: From e2517d11e83b66d1944b51e23a1ec7fec782b6ec Mon Sep 17 00:00:00 2001 From: David Date: Tue, 11 Jun 2024 20:01:23 +0200 Subject: [PATCH 007/176] chore: add include_icons jinja global --- frappe/hooks.py | 8 ++++---- frappe/templates/base.html | 14 +++++--------- frappe/utils/jinja_globals.py | 19 +++++++++++++++++++ frappe/website/utils.py | 2 +- frappe/www/app.html | 16 ++++++---------- frappe/www/app.py | 15 +++++++-------- 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index 7a97b3ece8..74c3a7a974 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -33,8 +33,8 @@ app_include_css = [ "report.bundle.css", ] app_include_icons = [ - "frappe/icons/timeless/icons.svg", - "frappe/icons/espresso/icons.svg", + "/assets/frappe/icons/timeless/icons.svg", + "/assets/frappe/icons/espresso/icons.svg", ] doctype_js = { @@ -45,8 +45,8 @@ doctype_js = { web_include_js = ["website_script.js"] web_include_css = [] web_include_icons = [ - "frappe/icons/timeless/icons.svg", - "frappe/icons/espresso/icons.svg", + "/assets/frappe/icons/timeless/icons.svg", + "/assets/frappe/icons/espresso/icons.svg", ] email_css = ["email.bundle.css"] diff --git a/frappe/templates/base.html b/frappe/templates/base.html index 375f80e8c2..efde1ea594 100644 --- a/frappe/templates/base.html +++ b/frappe/templates/base.html @@ -87,21 +87,17 @@ ) }} {%- endblock -%} + + {%- for path in web_include_icons -%} + {{ include_icons(path) }} + {%- endfor -%} + {% block base_scripts %} - {{ include_script('frappe-web.bundle.js') }} {% endblock %} diff --git a/frappe/utils/jinja_globals.py b/frappe/utils/jinja_globals.py index 848f41c527..37b3a2c962 100644 --- a/frappe/utils/jinja_globals.py +++ b/frappe/utils/jinja_globals.py @@ -110,6 +110,25 @@ def include_script(path, preload=True): return f'' +def include_icons(path, preload=True): + """Get path of bundled svg icons files. + + If preload is specified the path will be added to preload headers so browsers can prefetch + assets.""" + path = bundled_asset(path) + + if preload: + import frappe + + frappe.local.preload_assets["icons"].append(path) + + return ( + '' + ) + + def include_style(path, rtl=None, preload=True): """Get path of bundled style files. diff --git a/frappe/website/utils.py b/frappe/website/utils.py index 0e4916023e..38d78c4aea 100644 --- a/frappe/website/utils.py +++ b/frappe/website/utils.py @@ -573,7 +573,7 @@ def add_preload_for_bundled_assets(response): version = get_build_version() links.extend( - f"; rel=preload; as=fetch; crossorigin" + f"<{svg}?v={version}>; rel=preload; as=fetch; crossorigin" for svg in frappe.local.preload_assets["icons"] ) diff --git a/frappe/www/app.html b/frappe/www/app.html index a2fef3362d..d9534be770 100644 --- a/frappe/www/app.html +++ b/frappe/www/app.html @@ -21,7 +21,7 @@ href="{{ favicon or "/assets/frappe/images/frappe-favicon.svg" }}" type="image/x-icon"> - {% for include in include_css -%} + {% for include in app_include_css -%} {{ include_style(include) }} {%- endfor -%} @@ -56,17 +56,13 @@ frappe.csrf_token = "{{ csrf_token }}"; - {%- for path in include_icons -%} - fetch(`/assets/{{ path }}?v=${window._version_number}`, { credentials: "same-origin" }) - .then((r) => r.text()) - .then((svg) => { - let svg_container = document.getElementById("all-symbols"); - svg_container.insertAdjacentHTML("beforeend", svg); - }); - {%- endfor -%} - {% for include in include_js %} + {%- for path in app_include_icons -%} + {{ include_icons(path) }} + {%- endfor -%} + + {% for include in app_include_js %} {{ include_script(include) }} {% endfor %} diff --git a/frappe/www/app.py b/frappe/www/app.py index 9fe9628f53..5f27c0cf01 100644 --- a/frappe/www/app.py +++ b/frappe/www/app.py @@ -46,21 +46,20 @@ def get_context(context): boot_json = json.dumps(boot_json) hooks = frappe.get_hooks() - include_js = hooks.get("app_include_js", []) + frappe.conf.get("app_include_js", []) - include_css = hooks.get("app_include_css", []) + frappe.conf.get("app_include_css", []) - include_icons = hooks.get("app_include_icons", []) - frappe.local.preload_assets["icons"].extend(include_icons) + app_include_js = hooks.get("app_include_js", []) + frappe.conf.get("app_include_js", []) + app_include_css = hooks.get("app_include_css", []) + frappe.conf.get("app_include_css", []) + app_include_icons = hooks.get("app_include_icons", []) if frappe.get_system_settings("enable_telemetry") and os.getenv("FRAPPE_SENTRY_DSN"): - include_js.append("sentry.bundle.js") + app_include_js.append("sentry.bundle.js") context.update( { "no_cache": 1, "build_version": frappe.utils.get_build_version(), - "include_js": include_js, - "include_css": include_css, - "include_icons": include_icons, + "app_include_js": app_include_js, + "app_include_css": app_include_css, + "app_include_icons": app_include_icons, "layout_direction": "rtl" if is_rtl() else "ltr", "lang": frappe.local.lang, "sounds": hooks["sounds"], From 527ac29c2edf748eabec90bdb4bc41af04e64b17 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Tue, 11 Jun 2024 17:54:50 +0530 Subject: [PATCH 008/176] feat: Send Mails via Frappe Mail --- .../doctype/email_account/email_account.json | 77 +++++++++++++++---- .../doctype/email_account/email_account.py | 9 ++- .../email/doctype/email_queue/email_queue.py | 63 ++++++++++++++- 3 files changed, 130 insertions(+), 19 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index c496bb34da..d1ad871755 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -2,7 +2,7 @@ "actions": [], "allow_rename": 1, "autoname": "field:email_account_name", - "creation": "2014-09-11 12:04:34.163728", + "creation": "2024-06-11 16:39:01.323289", "doctype": "DocType", "document_type": "Setup", "engine": "InnoDB", @@ -15,6 +15,11 @@ "column_break_3", "domain", "service", + "frappe_mail_site", + "authentication_section", + "api_key", + "column_break_ghqa", + "api_secret", "authentication_column", "auth_method", "authorize_api_access", @@ -50,19 +55,21 @@ "notify_if_unreplied", "unreplied_for_mins", "send_notification_to", - "outgoing_smtp_tab", - "outgoing_mail_settings", - "column_break_bidn", - "use_tls", - "use_ssl_for_outgoing", - "smtp_server", - "smtp_port", - "column_break_38", + "outgoing_tab", + "section_break_nesl", + "column_break_y6hx", + "column_break_h5pd", "default_outgoing", "always_use_account_email_id_as_sender", "always_use_account_name_as_sender_name", "send_unsubscribe_message", "track_email_status", + "outgoing_mail_settings", + "use_tls", + "use_ssl_for_outgoing", + "smtp_server", + "smtp_port", + "column_break_38", "no_smtp_authentication", "signature_section", "add_signature", @@ -289,6 +296,7 @@ "mandatory_depends_on": "notify_if_unreplied" }, { + "depends_on": "eval: doc.service != \"Frappe Mail\"", "fieldname": "outgoing_mail_settings", "fieldtype": "Section Break", "hide_days": 1, @@ -533,6 +541,7 @@ "label": "Brand Logo" }, { + "depends_on": "eval: doc.service != \"Frappe Mail\"", "fieldname": "authentication_column", "fieldtype": "Section Break", "label": "Authentication" @@ -624,20 +633,58 @@ "label": "Incoming (POP/IMAP)" }, { - "depends_on": "enable_outgoing", - "fieldname": "outgoing_smtp_tab", - "fieldtype": "Tab Break", - "label": "Outgoing (SMTP)" + "fieldname": "api_key", + "fieldtype": "Data", + "label": "API Key", + "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\"" }, { - "fieldname": "column_break_bidn", + "fieldname": "api_secret", + "fieldtype": "Password", + "label": "API Secret", + "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\"" + }, + { + "depends_on": "eval: doc.service == \"Frappe Mail\"", + "fieldname": "authentication_section", + "fieldtype": "Section Break", + "label": "Authentication" + }, + { + "fieldname": "column_break_ghqa", + "fieldtype": "Column Break" + }, + { + "default": "https://frappemail.com", + "depends_on": "eval: doc.service == \"Frappe Mail\"", + "fieldname": "frappe_mail_site", + "fieldtype": "Data", + "label": "Frappe Mail Site", + "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\"" + }, + { + "depends_on": "enable_outgoing", + "fieldname": "outgoing_tab", + "fieldtype": "Tab Break", + "label": "Outgoing" + }, + { + "fieldname": "section_break_nesl", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_y6hx", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_h5pd", "fieldtype": "Column Break" } ], "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-10 18:18:08.403133", + "modified": "2024-06-11 16:54:22.255325", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 3d226c31ed..f911505f12 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -61,6 +61,8 @@ class EmailAccount(Document): add_signature: DF.Check always_use_account_email_id_as_sender: DF.Check always_use_account_name_as_sender_name: DF.Check + api_key: DF.Data | None + api_secret: DF.Password | None append_emails_to_sent_folder: DF.Check append_to: DF.Link | None ascii_encode_password: DF.Check @@ -84,6 +86,7 @@ class EmailAccount(Document): enable_incoming: DF.Check enable_outgoing: DF.Check footer: DF.TextEditor | None + frappe_mail_site: DF.Data | None imap_folder: DF.Table[IMAPFolder] incoming_port: DF.Data | None initial_sync_count: DF.Literal["100", "250", "500"] @@ -152,7 +155,11 @@ class EmailAccount(Document): self.awaiting_password = 0 self.password = None - if not frappe.local.flags.in_install and not self.awaiting_password: + if ( + not frappe.local.flags.in_install + and not self.awaiting_password + and not self.service == "Frappe Mail" + ): if validate_oauth or self.password or self.smtp_server in ("127.0.0.1", "localhost"): if self.enable_incoming: self.get_incoming_server() diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index a142845223..2b75ff03ee 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -7,6 +7,7 @@ import traceback from contextlib import suppress from email.parser import Parser from email.policy import SMTP +from typing import TYPE_CHECKING import frappe from frappe import _, safe_encode, task @@ -16,6 +17,7 @@ from frappe.email.doctype.email_account.email_account import EmailAccount from frappe.email.email_body import add_attachment, get_email, get_formatted_html from frappe.email.queue import get_unsubcribed_url, get_unsubscribe_message from frappe.email.smtp import SMTPServer +from frappe.frappeclient import FrappeClient from frappe.model.document import Document from frappe.query_builder import DocType, Interval from frappe.query_builder.functions import Now @@ -34,6 +36,9 @@ from frappe.utils import ( from frappe.utils.deprecations import deprecated from frappe.utils.verified_command import get_signed_params +if TYPE_CHECKING: + from requests import Response + class EmailQueue(Document): # begin: auto-generated types @@ -168,8 +173,14 @@ class EmailQueue(Document): message = ctx.build_message(recipient.recipient) if method := get_hook_method("override_email_send"): method(self, self.sender, recipient.recipient, message) - else: - if not frappe.flags.in_test or frappe.flags.testing_email: + elif not frappe.flags.in_test or frappe.flags.testing_email: + if ctx.email_account_doc.service == "Frappe Mail": + ctx.frappe_mail.send( + sender=self.sender, + recipients=recipient.recipient, + message=message.decode("utf-8"), + ) + else: ctx.smtp_server.session.sendmail( from_addr=self.sender, to_addrs=recipient.recipient, @@ -240,7 +251,10 @@ class SendMailContext: def fetch_smtp_server(self): self.email_account_doc = self.queue_doc.get_email_account(raise_error=True) - if not self.smtp_server: + + if self.email_account_doc.service == "Frappe Mail": + self.frappe_mail = FrappeMail(self.email_account_doc) + elif not self.smtp_server: self.smtp_server = self.email_account_doc.get_smtp_server() def __enter__(self): @@ -802,3 +816,46 @@ class QueueBuilder: d["recipients"] = self.final_recipients() return d + + +class FrappeMail: + def __init__(self, email_account: "EmailAccount") -> None: + self.client = self.get_client(email_account) + self.frappe_mail_site = email_account.frappe_mail_site + + @staticmethod + def get_client(email_account: "EmailAccount") -> FrappeClient: + """Returns FrappeClient object for the given email account.""" + + if hasattr(frappe.local, "frappe_mail_clients"): + if client := frappe.local.frappe_mail_clients.get(email_account.name): + return client + else: + frappe.local.frappe_mail_clients = {} + + url = email_account.frappe_mail_site + api_key = email_account.api_key + api_secret = email_account.get_password("api_secret") + + client = FrappeClient(url, api_key=api_key, api_secret=api_secret) + frappe.local.frappe_mail_clients[email_account.name] = client + + return client + + def request( + self, + method: str, + endpoint: str, + data: dict | None = None, + timeout: int | tuple[int, int] = (60, 120), + ) -> "Response": + url = f"{self.frappe_mail_site}/{endpoint}" + response = self.client.session.request( + method=method, url=url, headers=self.client.headers, json=data, timeout=timeout + ) + return response + + def send(self, sender: str, recipients: str, message: str): + endpoint = "outbound/send-raw" + data = {"from": sender, "to": recipients, "raw_message": message} + self.request("POST", endpoint, data) From 991f75bb0b57305e98237df46bf09280cc3c55f0 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Tue, 18 Jun 2024 12:39:32 +0530 Subject: [PATCH 009/176] feat: Retrieve Mails from Frappe Mail --- .../doctype/email_account/email_account.json | 19 ++++-- .../doctype/email_account/email_account.py | 41 ++++++++---- .../email/doctype/email_queue/email_queue.py | 58 +++------------- frappe/email/frappemail.py | 67 +++++++++++++++++++ 4 files changed, 117 insertions(+), 68 deletions(-) create mode 100644 frappe/email/frappemail.py diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index d1ad871755..3359bbd73f 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -32,8 +32,11 @@ "login_id_is_different", "login_id", "incoming_popimap_tab", - "mailbox_settings", + "section_break_uc6h", "default_incoming", + "column_break_uynb", + "attachment_limit", + "mailbox_settings", "use_imap", "use_ssl", "validate_ssl_certificate", @@ -41,7 +44,6 @@ "email_server", "incoming_port", "column_break_18", - "attachment_limit", "email_sync_option", "initial_sync_count", "section_break_25", @@ -169,6 +171,7 @@ "options": "\nFrappe Mail\nGMail\nSendgrid\nSparkPost\nYahoo Mail\nOutlook.com\nYandex.Mail" }, { + "depends_on": "eval: doc.service != \"Frappe Mail\"", "fieldname": "mailbox_settings", "fieldtype": "Section Break", "hide_days": 1, @@ -630,7 +633,7 @@ "depends_on": "enable_incoming", "fieldname": "incoming_popimap_tab", "fieldtype": "Tab Break", - "label": "Incoming (POP/IMAP)" + "label": "Incoming" }, { "fieldname": "api_key", @@ -679,12 +682,20 @@ { "fieldname": "column_break_h5pd", "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_uc6h", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_uynb", + "fieldtype": "Column Break" } ], "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-11 16:54:22.255325", + "modified": "2024-06-18 19:24:11.767869", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index f911505f12..8eb8ca54ce 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -12,6 +12,7 @@ import frappe from frappe import _, are_emails_muted, safe_encode from frappe.desk.form import assign_to from frappe.email.doctype.email_domain.email_domain import EMAIL_DOMAIN_FIELDS +from frappe.email.frappemail import FrappeMail from frappe.email.receive import EmailServer, InboundMail, SentEmailInInboxError from frappe.email.smtp import SMTPServer from frappe.email.utils import get_port @@ -133,6 +134,9 @@ class EmailAccount(Document): if self.email_id: validate_email_address(self.email_id, True) + if self.service == "Frappe Mail" and self.use_imap: + self.use_imap = 0 + if self.login_id_is_different: if not self.login_id: frappe.throw(_("Login Id is required")) @@ -595,25 +599,34 @@ class EmailAccount(Document): if not self.enable_incoming: return [] - email_sync_rule = self.build_email_sync_rule() try: - email_server = self.get_incoming_server(in_receive=True, email_sync_rule=email_sync_rule) - if self.use_imap: - # process all given imap folder - for folder in self.imap_folder: - if email_server.select_imap_folder(folder.folder_name): - email_server.settings["uid_validity"] = folder.uidvalidity - messages = email_server.get_messages(folder=f'"{folder.folder_name}"') or {} - process_mail(messages, folder.append_to) - else: - # process the pop3 account - messages = email_server.get_messages() or {} + if self.service == "Frappe Mail": + fm_client = FrappeMail( + self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") + ) + messages = fm_client.pull(self.email_id) process_mail(messages) - # close connection to mailserver - email_server.logout() + else: + email_sync_rule = self.build_email_sync_rule() + email_server = self.get_incoming_server(in_receive=True, email_sync_rule=email_sync_rule) + if self.use_imap: + # process all given imap folder + for folder in self.imap_folder: + if email_server.select_imap_folder(folder.folder_name): + email_server.settings["uid_validity"] = folder.uidvalidity + messages = email_server.get_messages(folder=f'"{folder.folder_name}"') or {} + process_mail(messages, folder.append_to) + else: + # process the pop3 account + messages = email_server.get_messages() or {} + process_mail(messages) + + # close connection to mailserver + email_server.logout() except Exception: self.log_error(title=_("Error while connecting to email account {0}").format(self.name)) return [] + return mails def handle_bad_emails(self, uid, raw, reason): diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index 2b75ff03ee..57280b7a5f 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -7,7 +7,6 @@ import traceback from contextlib import suppress from email.parser import Parser from email.policy import SMTP -from typing import TYPE_CHECKING import frappe from frappe import _, safe_encode, task @@ -15,9 +14,9 @@ from frappe.core.utils import html2text from frappe.database.database import savepoint from frappe.email.doctype.email_account.email_account import EmailAccount from frappe.email.email_body import add_attachment, get_email, get_formatted_html +from frappe.email.frappemail import FrappeMail from frappe.email.queue import get_unsubcribed_url, get_unsubscribe_message from frappe.email.smtp import SMTPServer -from frappe.frappeclient import FrappeClient from frappe.model.document import Document from frappe.query_builder import DocType, Interval from frappe.query_builder.functions import Now @@ -36,9 +35,6 @@ from frappe.utils import ( from frappe.utils.deprecations import deprecated from frappe.utils.verified_command import get_signed_params -if TYPE_CHECKING: - from requests import Response - class EmailQueue(Document): # begin: auto-generated types @@ -175,7 +171,7 @@ class EmailQueue(Document): method(self, self.sender, recipient.recipient, message) elif not frappe.flags.in_test or frappe.flags.testing_email: if ctx.email_account_doc.service == "Frappe Mail": - ctx.frappe_mail.send( + ctx.fm_client.send( sender=self.sender, recipients=recipient.recipient, message=message.decode("utf-8"), @@ -253,7 +249,12 @@ class SendMailContext: self.email_account_doc = self.queue_doc.get_email_account(raise_error=True) if self.email_account_doc.service == "Frappe Mail": - self.frappe_mail = FrappeMail(self.email_account_doc) + site = self.email_account_doc.frappe_mail_site + mailbox = self.email_account_doc.email_id + api_key = self.email_account_doc.api_key + api_secret = self.email_account_doc.get_password("api_secret") + self.fm_client = FrappeMail(site, mailbox, api_key, api_secret) + elif not self.smtp_server: self.smtp_server = self.email_account_doc.get_smtp_server() @@ -816,46 +817,3 @@ class QueueBuilder: d["recipients"] = self.final_recipients() return d - - -class FrappeMail: - def __init__(self, email_account: "EmailAccount") -> None: - self.client = self.get_client(email_account) - self.frappe_mail_site = email_account.frappe_mail_site - - @staticmethod - def get_client(email_account: "EmailAccount") -> FrappeClient: - """Returns FrappeClient object for the given email account.""" - - if hasattr(frappe.local, "frappe_mail_clients"): - if client := frappe.local.frappe_mail_clients.get(email_account.name): - return client - else: - frappe.local.frappe_mail_clients = {} - - url = email_account.frappe_mail_site - api_key = email_account.api_key - api_secret = email_account.get_password("api_secret") - - client = FrappeClient(url, api_key=api_key, api_secret=api_secret) - frappe.local.frappe_mail_clients[email_account.name] = client - - return client - - def request( - self, - method: str, - endpoint: str, - data: dict | None = None, - timeout: int | tuple[int, int] = (60, 120), - ) -> "Response": - url = f"{self.frappe_mail_site}/{endpoint}" - response = self.client.session.request( - method=method, url=url, headers=self.client.headers, json=data, timeout=timeout - ) - return response - - def send(self, sender: str, recipients: str, message: str): - endpoint = "outbound/send-raw" - data = {"from": sender, "to": recipients, "raw_message": message} - self.request("POST", endpoint, data) diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py new file mode 100644 index 0000000000..9831ca0e57 --- /dev/null +++ b/frappe/email/frappemail.py @@ -0,0 +1,67 @@ +from typing import TYPE_CHECKING + +import frappe +from frappe.frappeclient import FrappeClient + +if TYPE_CHECKING: + from requests import Response + + +class FrappeMail: + """Class to interact with the Frappe Mail API.""" + + def __init__(self, site: str, mailbox: str, api_key: str, api_secret: str) -> None: + self.site = site + self.client = self.get_client(site, mailbox, api_key, api_secret) + + @staticmethod + def get_client(site: str, mailbox: str, api_key: str, api_secret: str) -> FrappeClient: + """Returns FrappeClient object for the given email account.""" + + if hasattr(frappe.local, "frappe_mail_clients"): + if client := frappe.local.frappe_mail_clients.get(mailbox): + return client + else: + frappe.local.frappe_mail_clients = {} + + client = FrappeClient(url=site, api_key=api_key, api_secret=api_secret) + frappe.local.frappe_mail_clients[mailbox] = client + + return client + + def request( + self, + method: str, + endpoint: str, + params: dict | None = None, + data: dict | None = None, + json: dict | None = None, + headers: dict[str, str] | None = None, + timeout: int | tuple[int, int] = (60, 120), + ) -> "Response": + """Makes a HTTP request to the Frappe Mail API.""" + + url = f"{self.site}/{endpoint}" + headers = headers or {} + headers.update(self.client.headers) + response = self.client.session.request( + method=method, url=url, params=params, data=data, json=json, headers=headers, timeout=timeout + ) + return response + + def send(self, sender: str, recipients: str, message: str) -> None: + """Sends an email using the Frappe Mail API.""" + + endpoint = "outbound/send-raw" + json_data = {"from": sender, "to": recipients, "raw_message": message} + self.request("POST", endpoint=endpoint, json=json_data) + + def pull(self, mailbox: str, limit: int = 50) -> dict[str, list]: + """Returns the emails for the given mailbox.""" + + endpoint = "inbound/pull" + data = {"mailbox": mailbox, "limit": limit} + headers = {"X-Site": frappe.utils.get_url()} + response = self.request("GET", endpoint=endpoint, data=data, headers=headers) + + return {"latest_messages": response.json().get("message", [])} From 2f66425b1d5c0846091c3ec80bc123a6f967ddd1 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 19 Jun 2024 11:56:53 +0530 Subject: [PATCH 010/176] chore: provide `last_synced_at` while retrieving mails --- frappe/email/doctype/email_account/email_account.json | 10 +++++++++- frappe/email/doctype/email_account/email_account.py | 4 +++- frappe/email/frappemail.py | 10 ++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index 3359bbd73f..4d1c32dc12 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -36,6 +36,7 @@ "default_incoming", "column_break_uynb", "attachment_limit", + "last_synced_at", "mailbox_settings", "use_imap", "use_ssl", @@ -690,12 +691,19 @@ { "fieldname": "column_break_uynb", "fieldtype": "Column Break" + }, + { + "depends_on": "eval: doc.service == \"Frappe Mail\"", + "fieldname": "last_synced_at", + "fieldtype": "Datetime", + "label": "Last Synced At", + "read_only": 1 } ], "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-18 19:24:11.767869", + "modified": "2024-06-19 11:50:56.886640", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 8eb8ca54ce..db7ae7a711 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -91,6 +91,7 @@ class EmailAccount(Document): imap_folder: DF.Table[IMAPFolder] incoming_port: DF.Data | None initial_sync_count: DF.Literal["100", "250", "500"] + last_synced_at: DF.Datetime | None login_id: DF.Data | None login_id_is_different: DF.Check no_failed: DF.Int @@ -604,8 +605,9 @@ class EmailAccount(Document): fm_client = FrappeMail( self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") ) - messages = fm_client.pull(self.email_id) + messages = fm_client.pull(self.email_id, last_synced_at=self.last_synced_at) process_mail(messages) + self.db_set("last_synced_at", messages["last_synced_at"], update_modified=False) else: email_sync_rule = self.build_email_sync_rule() email_server = self.get_incoming_server(in_receive=True, email_sync_rule=email_sync_rule) diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index 9831ca0e57..cfefabd069 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -56,12 +56,14 @@ class FrappeMail: json_data = {"from": sender, "to": recipients, "raw_message": message} self.request("POST", endpoint=endpoint, json=json_data) - def pull(self, mailbox: str, limit: int = 50) -> dict[str, list]: + def pull( + self, mailbox: str, limit: int = 50, last_synced_at: str | None = None + ) -> dict[str, list[str] | str]: """Returns the emails for the given mailbox.""" endpoint = "inbound/pull" - data = {"mailbox": mailbox, "limit": limit} + data = {"mailbox": mailbox, "limit": limit, "last_synced_at": last_synced_at} headers = {"X-Site": frappe.utils.get_url()} - response = self.request("GET", endpoint=endpoint, data=data, headers=headers) + response = self.request("GET", endpoint=endpoint, data=data, headers=headers).json()["message"] - return {"latest_messages": response.json().get("message", [])} + return {"latest_messages": response["mails"], "last_synced_at": response["last_synced_at"]} From 42320df5f998b98aa1c74f0a16f73f21dc9a943f Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 19 Jun 2024 12:45:43 +0530 Subject: [PATCH 011/176] fix: log exception --- frappe/email/frappemail.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index cfefabd069..d9f3af2b85 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -7,6 +7,15 @@ if TYPE_CHECKING: from requests import Response +class FrappeMailException(Exception): + """Exception raised for errors in the Frappe Mail API.""" + + def __init__(self, message: str, status_code: int) -> None: + self.message = message + self.status_code = status_code + super().__init__(message) + + class FrappeMail: """Class to interact with the Frappe Mail API.""" @@ -38,6 +47,7 @@ class FrappeMail: json: dict | None = None, headers: dict[str, str] | None = None, timeout: int | tuple[int, int] = (60, 120), + raise_exception: bool = True, ) -> "Response": """Makes a HTTP request to the Frappe Mail API.""" @@ -47,6 +57,10 @@ class FrappeMail: response = self.client.session.request( method=method, url=url, params=params, data=data, json=json, headers=headers, timeout=timeout ) + + if not response.ok and raise_exception: + raise FrappeMailException(response.text, response.status_code) + return response def send(self, sender: str, recipients: str, message: str) -> None: From 5f5e5e1f6161f95c3ecd38c3ee5b637d1c59124e Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 19 Jun 2024 14:58:22 +0530 Subject: [PATCH 012/176] fix: use `urljoin` to join site and endpoint --- frappe/email/frappemail.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index d9f3af2b85..f0a5645ba5 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING +from urllib.parse import urljoin import frappe from frappe.frappeclient import FrappeClient @@ -24,7 +25,7 @@ class FrappeMail: self.client = self.get_client(site, mailbox, api_key, api_secret) @staticmethod - def get_client(site: str, mailbox: str, api_key: str, api_secret: str) -> FrappeClient: + def get_client(site: str, mailbox: str, api_key: str, api_secret: str) -> "FrappeClient": """Returns FrappeClient object for the given email account.""" if hasattr(frappe.local, "frappe_mail_clients"): @@ -51,7 +52,7 @@ class FrappeMail: ) -> "Response": """Makes a HTTP request to the Frappe Mail API.""" - url = f"{self.site}/{endpoint}" + url = urljoin(self.site, endpoint) headers = headers or {} headers.update(self.client.headers) response = self.client.session.request( From fca0cf7b01708a6f27f7e1eefeae68b34d640a95 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 19 Jun 2024 17:33:11 +0530 Subject: [PATCH 013/176] fix: validate Frappe Mail settings on Email Account save --- .../doctype/email_account/email_account.py | 12 ++++++--- frappe/email/frappemail.py | 25 ++++++++++++++----- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index db7ae7a711..ee5e8cb12b 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -135,8 +135,14 @@ class EmailAccount(Document): if self.email_id: validate_email_address(self.email_id, True) - if self.service == "Frappe Mail" and self.use_imap: - self.use_imap = 0 + if self.service == "Frappe Mail": + if self.use_imap: + self.use_imap = 0 + + fm_client = FrappeMail( + self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") + ) + fm_client.validate(for_inbound=self.enable_incoming, for_outbound=self.enable_outgoing) if self.login_id_is_different: if not self.login_id: @@ -605,7 +611,7 @@ class EmailAccount(Document): fm_client = FrappeMail( self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") ) - messages = fm_client.pull(self.email_id, last_synced_at=self.last_synced_at) + messages = fm_client.pull(last_synced_at=self.last_synced_at) process_mail(messages) self.db_set("last_synced_at", messages["last_synced_at"], update_modified=False) else: diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index f0a5645ba5..7323b52f0a 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -22,11 +22,12 @@ class FrappeMail: def __init__(self, site: str, mailbox: str, api_key: str, api_secret: str) -> None: self.site = site + self.mailbox = mailbox self.client = self.get_client(site, mailbox, api_key, api_secret) @staticmethod def get_client(site: str, mailbox: str, api_key: str, api_secret: str) -> "FrappeClient": - """Returns FrappeClient object for the given email account.""" + """Returns a FrappeClient instance.""" if hasattr(frappe.local, "frappe_mail_clients"): if client := frappe.local.frappe_mail_clients.get(mailbox): @@ -64,6 +65,20 @@ class FrappeMail: return response + def validate(self, for_outbound: bool = False, for_inbound: bool = False) -> None: + """Validates the mailbox for inbound and outbound emails.""" + + endpoint = "auth/validate" + data = {"mailbox": self.mailbox, "for_outbound": for_outbound, "for_inbound": for_inbound} + response = self.request("POST", endpoint=endpoint, data=data, raise_exception=False) + + if not response.ok: + if exception := response.json().get("exception"): + if exception == "frappe.exceptions.AuthenticationError": + exception += ": Invalid API Key or Secret" + + frappe.throw(title="Frappe Mail", msg=exception) + def send(self, sender: str, recipients: str, message: str) -> None: """Sends an email using the Frappe Mail API.""" @@ -71,13 +86,11 @@ class FrappeMail: json_data = {"from": sender, "to": recipients, "raw_message": message} self.request("POST", endpoint=endpoint, json=json_data) - def pull( - self, mailbox: str, limit: int = 50, last_synced_at: str | None = None - ) -> dict[str, list[str] | str]: - """Returns the emails for the given mailbox.""" + def pull(self, limit: int = 50, last_synced_at: str | None = None) -> dict[str, list[str] | str]: + """Pulls emails from the mailbox using the Frappe Mail API.""" endpoint = "inbound/pull" - data = {"mailbox": mailbox, "limit": limit, "last_synced_at": last_synced_at} + data = {"mailbox": self.mailbox, "limit": limit, "last_synced_at": last_synced_at} headers = {"X-Site": frappe.utils.get_url()} response = self.request("GET", endpoint=endpoint, data=data, headers=headers).json()["message"] From 5a4a36591ef43a6d6927452911a82273ac3da51c Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 20 Jun 2024 13:01:13 +0530 Subject: [PATCH 014/176] fix: always use email id as sender --- .../doctype/email_account/email_account.json | 21 +++++++++---------- .../doctype/email_account/email_account.py | 3 +++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index 4d1c32dc12..e4267a78d7 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -672,14 +672,6 @@ "fieldtype": "Tab Break", "label": "Outgoing" }, - { - "fieldname": "section_break_nesl", - "fieldtype": "Section Break" - }, - { - "fieldname": "column_break_y6hx", - "fieldtype": "Column Break" - }, { "fieldname": "column_break_h5pd", "fieldtype": "Column Break" @@ -696,14 +688,21 @@ "depends_on": "eval: doc.service == \"Frappe Mail\"", "fieldname": "last_synced_at", "fieldtype": "Datetime", - "label": "Last Synced At", - "read_only": 1 + "label": "Last Synced At" + }, + { + "fieldname": "section_break_nesl", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_y6hx", + "fieldtype": "Column Break" } ], "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-19 11:50:56.886640", + "modified": "2024-06-20 16:29:23.704289", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index ee5e8cb12b..852dc3529d 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -139,6 +139,9 @@ class EmailAccount(Document): if self.use_imap: self.use_imap = 0 + if not self.always_use_account_email_id_as_sender: + self.always_use_account_email_id_as_sender = 1 + fm_client = FrappeMail( self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") ) From 8143595a2f8e778b53e4f0d315854e314b088617 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 20 Jun 2024 16:58:04 +0530 Subject: [PATCH 015/176] chore: update Frappe Mail pull endpoint --- frappe/email/frappemail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index 7323b52f0a..9ca1411b59 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -89,7 +89,7 @@ class FrappeMail: def pull(self, limit: int = 50, last_synced_at: str | None = None) -> dict[str, list[str] | str]: """Pulls emails from the mailbox using the Frappe Mail API.""" - endpoint = "inbound/pull" + endpoint = "inbound/pull-raw" data = {"mailbox": self.mailbox, "limit": limit, "last_synced_at": last_synced_at} headers = {"X-Site": frappe.utils.get_url()} response = self.request("GET", endpoint=endpoint, data=data, headers=headers).json()["message"] From 34be31f393769a191494fa70e70fb5b19e732d2a Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 21 Jun 2024 13:04:59 +0530 Subject: [PATCH 016/176] fix: use UTC instead of system timezone --- frappe/email/frappemail.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index 9ca1411b59..ecec7e0564 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -1,8 +1,12 @@ +from datetime import datetime from typing import TYPE_CHECKING from urllib.parse import urljoin +import pytz + import frappe from frappe.frappeclient import FrappeClient +from frappe.utils import convert_utc_to_system_timezone, get_datetime, get_datetime_str, get_system_timezone if TYPE_CHECKING: from requests import Response @@ -90,8 +94,24 @@ class FrappeMail: """Pulls emails from the mailbox using the Frappe Mail API.""" endpoint = "inbound/pull-raw" + if last_synced_at: + last_synced_at = convert_to_utc(last_synced_at) + data = {"mailbox": self.mailbox, "limit": limit, "last_synced_at": last_synced_at} headers = {"X-Site": frappe.utils.get_url()} response = self.request("GET", endpoint=endpoint, data=data, headers=headers).json()["message"] + last_synced_at = convert_utc_to_system_timezone(get_datetime(response["last_synced_at"])) - return {"latest_messages": response["mails"], "last_synced_at": response["last_synced_at"]} + return {"latest_messages": response["mails"], "last_synced_at": last_synced_at} + + +def convert_to_utc(date_time: datetime | str, from_timezone: str | None = None) -> str: + """Converts datetime to UTC timezone.""" + + dt = ( + pytz.timezone(from_timezone or get_system_timezone()) + .localize(get_datetime(date_time)) + .astimezone(pytz.utc) + ) + + return get_datetime_str(dt) From 2819a2d92776a98693bf07961198ec88ce7de310 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sat, 22 Jun 2024 08:55:02 +0530 Subject: [PATCH 017/176] fix(ux): Email Account form --- .../doctype/email_account/email_account.json | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index e4267a78d7..0ca9ba6db0 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -8,14 +8,14 @@ "engine": "InnoDB", "field_order": [ "account_section", - "email_id", - "email_account_name", + "service", + "frappe_mail_site", + "domain", "enable_incoming", "enable_outgoing", "column_break_3", - "domain", - "service", - "frappe_mail_site", + "email_id", + "email_account_name", "authentication_section", "api_key", "column_break_ghqa", @@ -59,10 +59,8 @@ "unreplied_for_mins", "send_notification_to", "outgoing_tab", - "section_break_nesl", - "column_break_y6hx", - "column_break_h5pd", "default_outgoing", + "column_break_h5pd", "always_use_account_email_id_as_sender", "always_use_account_name_as_sender_name", "send_unsubscribe_message", @@ -689,20 +687,12 @@ "fieldname": "last_synced_at", "fieldtype": "Datetime", "label": "Last Synced At" - }, - { - "fieldname": "section_break_nesl", - "fieldtype": "Section Break" - }, - { - "fieldname": "column_break_y6hx", - "fieldtype": "Column Break" } ], "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-20 16:29:23.704289", + "modified": "2024-06-22 08:51:12.977896", "modified_by": "Administrator", "module": "Email", "name": "Email Account", From 13b1a4008ca4fcaf06e313b70254ffd5ecf06265 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 14:17:54 +0200 Subject: [PATCH 018/176] fix: translation in doctype.js fix: translation in doctype.js --- frappe/core/doctype/doctype/doctype.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.js b/frappe/core/doctype/doctype/doctype.js index f672db1f92..8ff8b8a9c0 100644 --- a/frappe/core/doctype/doctype/doctype.js +++ b/frappe/core/doctype/doctype/doctype.js @@ -62,7 +62,7 @@ frappe.ui.form.on("DocType", { } } - const customize_form_link = "Customize Form"; + const customize_form_link = "__(Customize Form)"; if (!frappe.boot.developer_mode && !frm.doc.custom) { // make the document read-only frm.set_read_only(); From 54a95dae5be84dc82f6c0b800067260e1f2ceb7c Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 16:11:06 +0200 Subject: [PATCH 019/176] fix: translation in dashboard_utils.js fix: translation in dashboard_utils.js --- frappe/public/js/frappe/utils/dashboard_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/utils/dashboard_utils.js b/frappe/public/js/frappe/utils/dashboard_utils.js index 1058101fff..89c53ee0ff 100644 --- a/frappe/public/js/frappe/utils/dashboard_utils.js +++ b/frappe/public/js/frappe/utils/dashboard_utils.js @@ -160,7 +160,7 @@ frappe.dashboard_utils = { fieldtype: "HTML", fieldname: "description", options: `
-

Set dynamic filter values in JavaScript for the required fields here. +

${__("Set dynamic filter values in JavaScript for the required fields here.")}

Ex: frappe.defaults.get_user_default("Company") From 1ada5211b94de810c4b93119d0fb64bf14449f5b Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 24 Jun 2024 06:16:55 +0530 Subject: [PATCH 020/176] refactor: method to get frappe mail client instance --- .../doctype/email_account/email_account.py | 19 +++++++++++-------- .../email/doctype/email_queue/email_queue.py | 14 ++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 852dc3529d..cd4cf4d11a 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -142,10 +142,8 @@ class EmailAccount(Document): if not self.always_use_account_email_id_as_sender: self.always_use_account_email_id_as_sender = 1 - fm_client = FrappeMail( - self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") - ) - fm_client.validate(for_inbound=self.enable_incoming, for_outbound=self.enable_outgoing) + frappe_mail_client = self.get_frappe_mail_client() + frappe_mail_client.validate(for_inbound=self.enable_incoming, for_outbound=self.enable_outgoing) if self.login_id_is_different: if not self.login_id: @@ -519,6 +517,13 @@ class EmailAccount(Document): config = self.sendmail_config() return SMTPServer(**config) + def get_frappe_mail_client(self): + return self._frappe_mail_client + + @functools.cached_property + def _frappe_mail_client(self): + return FrappeMail(self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret")) + def remove_unpicklable_values(self, state): super().remove_unpicklable_values(state) state.pop("_smtp_server_instance", None) @@ -611,10 +616,8 @@ class EmailAccount(Document): try: if self.service == "Frappe Mail": - fm_client = FrappeMail( - self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") - ) - messages = fm_client.pull(last_synced_at=self.last_synced_at) + frappe_mail_client = self.get_frappe_mail_client() + messages = frappe_mail_client.pull(last_synced_at=self.last_synced_at) process_mail(messages) self.db_set("last_synced_at", messages["last_synced_at"], update_modified=False) else: diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index 57280b7a5f..0ffea902e2 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -14,7 +14,6 @@ from frappe.core.utils import html2text from frappe.database.database import savepoint from frappe.email.doctype.email_account.email_account import EmailAccount from frappe.email.email_body import add_attachment, get_email, get_formatted_html -from frappe.email.frappemail import FrappeMail from frappe.email.queue import get_unsubcribed_url, get_unsubscribe_message from frappe.email.smtp import SMTPServer from frappe.model.document import Document @@ -160,7 +159,7 @@ class EmailQueue(Document): return with SendMailContext(self, smtp_server_instance) as ctx: - ctx.fetch_smtp_server() + ctx.fetch_outgoing_server() message = None for recipient in self.recipients: if recipient.is_mail_sent(): @@ -171,7 +170,7 @@ class EmailQueue(Document): method(self, self.sender, recipient.recipient, message) elif not frappe.flags.in_test or frappe.flags.testing_email: if ctx.email_account_doc.service == "Frappe Mail": - ctx.fm_client.send( + ctx.frappe_mail_client.send( sender=self.sender, recipients=recipient.recipient, message=message.decode("utf-8"), @@ -245,16 +244,11 @@ class SendMailContext: rec.recipient for rec in self.queue_doc.recipients if rec.is_mail_sent() ) - def fetch_smtp_server(self): + def fetch_outgoing_server(self): self.email_account_doc = self.queue_doc.get_email_account(raise_error=True) if self.email_account_doc.service == "Frappe Mail": - site = self.email_account_doc.frappe_mail_site - mailbox = self.email_account_doc.email_id - api_key = self.email_account_doc.api_key - api_secret = self.email_account_doc.get_password("api_secret") - self.fm_client = FrappeMail(site, mailbox, api_key, api_secret) - + self.frappe_mail_client = self.email_account_doc.get_frappe_mail_client() elif not self.smtp_server: self.smtp_server = self.email_account_doc.get_smtp_server() From cdacca91a6148a34d46a48b28ff0f044281f1c40 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 27 Jun 2024 11:33:56 +0000 Subject: [PATCH 021/176] refactor: get_linked_docs - Cleaner logic flows - Better variables naming & use of standard/cleaner APIs - Use get_list to show only permitted docs --- frappe/desk/form/linked_with.py | 154 +++++++++++++++----------------- 1 file changed, 70 insertions(+), 84 deletions(-) diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 96c9cacd64..c68388aa70 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -421,99 +421,85 @@ def get_linked_docs(doctype: str, name: str, linkinfo: dict | None = None) -> di if not linkinfo: return results - for dt, link in linkinfo.items(): - filters = [] - link["doctype"] = dt - try: - link_meta_bundle = frappe.desk.form.load.get_meta_bundle(dt) - except Exception as e: - if isinstance(e, frappe.DoesNotExistError): - frappe.clear_last_message() + is_target_doctype_table = frappe.get_meta(doctype).istable + + for linked_doctype, link_context in linkinfo.items(): + linked_doctype_meta = frappe.get_meta(linked_doctype) + + if linked_doctype_meta.issingle: continue - linkmeta = link_meta_bundle[0] - if not linkmeta.get("issingle"): - fields = [ - d.fieldname - for d in linkmeta.get( - "fields", - { - "in_list_view": 1, - "fieldtype": ["not in", ("Image", "HTML", "Button", *frappe.model.table_fields)], - }, - ) - ] + ["name", "modified", "docstatus"] + filters = [] + ret = None + parent_info = None - if link.get("add_fields"): - fields += link["add_fields"] + fields = [ + d.fieldname + for d in linked_doctype_meta.get( + "fields", + { + "in_list_view": 1, + "fieldtype": ["not in", ("Image", "HTML", "Button", *frappe.model.table_fields)], + }, + ) + ] + ["name", "modified", "docstatus"] - fields = [f"`tab{dt}`.`{sf.strip()}`" for sf in fields if sf and "`tab" not in sf] + if add_fields := link_context.get("add_fields"): + fields += add_fields - try: - if link.get("filters"): - ret = frappe.get_all( - doctype=dt, fields=fields, filters=link.get("filters"), order_by=None - ) + fields = [f"`tab{linked_doctype}`.`{sf.strip()}`" for sf in fields if sf and "`tab" not in sf] - elif link.get("get_parent"): - ret = None - - # check for child table - if not frappe.get_meta(doctype).istable: - continue - - me = frappe.db.get_value( - doctype, name, ["parenttype", "parent"], as_dict=True, order_by=None - ) - if me and me.parenttype == dt: - ret = frappe.get_all( - doctype=dt, fields=fields, filters=[[dt, "name", "=", me.parent]], order_by=None - ) - - elif link.get("child_doctype"): - or_filters = [ - [link.get("child_doctype"), link_fieldnames, "=", name] - for link_fieldnames in link.get("fieldname") - ] - - # dynamic link - if link.get("doctype_fieldname"): - filters.append( - [link.get("child_doctype"), link.get("doctype_fieldname"), "=", doctype] - ) - - ret = frappe.get_all( - doctype=dt, - fields=fields, - filters=filters, - or_filters=or_filters, - distinct=True, - order_by=None, - ) - - else: - link_fieldnames = link.get("fieldname") - if link_fieldnames: - if isinstance(link_fieldnames, str): - link_fieldnames = [link_fieldnames] - or_filters = [[dt, fieldname, "=", name] for fieldname in link_fieldnames] - # dynamic link - if link.get("doctype_fieldname"): - filters.append([dt, link.get("doctype_fieldname"), "=", doctype]) - ret = frappe.get_all( - doctype=dt, fields=fields, filters=filters, or_filters=or_filters, order_by=None - ) - - else: - ret = None - - except frappe.PermissionError: - frappe.clear_last_message() + if filters_ctx := link_context.get("filters"): + ret = frappe.get_list(doctype=linked_doctype, fields=fields, filters=filters_ctx, order_by=None) + elif link_context.get("get_parent"): + # check for child table + if not is_target_doctype_table: continue - if ret: - results[dt] = ret + parent_info = parent_info or frappe.db.get_value( + doctype, name, ["parenttype", "parent"], as_dict=True, order_by=None + ) + + if parent_info and parent_info.parenttype == linked_doctype: + ret = frappe.get_list( + doctype=linked_doctype, + fields=fields, + filters=[[linked_doctype, "name", "=", parent_info.parent]], + order_by=None, + ) + + elif child_doctype := link_context.get("child_doctype"): + or_filters = [ + [child_doctype, link_fieldnames, "=", name] for link_fieldnames in link_context["fieldname"] + ] + + # dynamic link_context + if doctype_fieldname := link_context.get("doctype_fieldname"): + filters.append([child_doctype, doctype_fieldname, "=", doctype]) + + ret = frappe.get_list( + doctype=linked_doctype, + fields=fields, + filters=filters, + or_filters=or_filters, + distinct=True, + order_by=None, + ) + + elif link_fieldnames := link_context.get("fieldname"): + if isinstance(link_fieldnames, str): + link_fieldnames = [link_fieldnames] + or_filters = [[linked_doctype, fieldname, "=", name] for fieldname in link_fieldnames] + # dynamic link_context + if doctype_fieldname := link_context.get("doctype_fieldname"): + filters.append([linked_doctype, doctype_fieldname, "=", doctype]) + ret = frappe.get_list( + doctype=linked_doctype, fields=fields, filters=filters, or_filters=or_filters, order_by=None + ) + + if ret: + results[linked_doctype] = ret return results From 317ef25a3e0b854a7fda5c1a151a28631523cec4 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 24 Jun 2024 07:43:05 +0530 Subject: [PATCH 022/176] feat: use OAuth to login to Frappe Mail --- .../doctype/email_account/email_account.js | 31 +++++++- .../doctype/email_account/email_account.json | 69 +++++++++--------- .../doctype/email_account/email_account.py | 46 ++++++++---- .../email/doctype/email_queue/email_queue.py | 23 ++++-- frappe/email/frappemail.py | 71 ++++++++++++------- 5 files changed, 158 insertions(+), 82 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.js b/frappe/email/doctype/email_account/email_account.js index 959a1908a0..3a0baa9564 100644 --- a/frappe/email/doctype/email_account/email_account.js +++ b/frappe/email/doctype/email_account/email_account.js @@ -1,4 +1,24 @@ frappe.email_defaults = { + "Frappe Mail": { + domain: null, + password: null, + awaiting_password: 0, + ascii_encode_password: 0, + login_id_is_different: 0, + login_id: null, + use_imap: 0, + use_ssl: 0, + validate_ssl_certificate: 0, + use_starttls: 0, + email_server: null, + incoming_port: 0, + always_use_account_email_id_as_sender: 1, + use_tls: 0, + use_ssl_for_outgoing: 0, + smtp_server: null, + smtp_port: null, + no_smtp_authentication: 0, + }, GMail: { email_server: "imap.gmail.com", incoming_port: 993, @@ -144,11 +164,11 @@ frappe.ui.form.on("Email Account", { frm.refresh_field("imap_folder"); } set_default_max_attachment_size(frm); - frm.events.show_oauth_authorization_message(frm); }, refresh: function (frm) { frm.events.enable_incoming(frm); + frm.events.show_oauth_authorization_message(frm); if (frappe.route_flags.delete_user_from_locals && frappe.route_flags.linked_user) { delete frappe.route_flags.delete_user_from_locals; @@ -169,6 +189,15 @@ frappe.ui.form.on("Email Account", { oauth_access(frm); }, + validate_frappe_mail_settings: function (frm) { + if (frm.doc.service == "Frappe Mail") { + frappe.call({ + doc: frm.doc, + method: "validate_frappe_mail_settings", + }); + } + }, + show_oauth_authorization_message(frm) { if (frm.doc.auth_method === "OAuth" && frm.doc.connected_app) { frappe.call({ diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index 0ca9ba6db0..dd244285c1 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -8,25 +8,24 @@ "engine": "InnoDB", "field_order": [ "account_section", - "service", - "frappe_mail_site", - "domain", + "email_id", + "email_account_name", "enable_incoming", "enable_outgoing", "column_break_3", - "email_id", - "email_account_name", - "authentication_section", - "api_key", - "column_break_ghqa", - "api_secret", + "service", + "domain", + "frappe_mail_site", "authentication_column", "auth_method", "authorize_api_access", + "validate_frappe_mail_settings", "password", "awaiting_password", "ascii_encode_password", "column_break_10", + "api_key", + "api_secret", "connected_app", "connected_user", "login_id_is_different", @@ -100,6 +99,7 @@ }, { "default": "0", + "depends_on": "eval: doc.service != \"Frappe Mail\"", "fieldname": "login_id_is_different", "fieldtype": "Check", "hide_days": 1, @@ -115,7 +115,7 @@ "label": "Alternative Email ID" }, { - "depends_on": "eval: doc.auth_method === \"Basic\"", + "depends_on": "eval: doc.auth_method === \"Basic\" && doc.service != \"Frappe Mail\"", "fieldname": "password", "fieldtype": "Password", "hide_days": 1, @@ -124,7 +124,7 @@ }, { "default": "0", - "depends_on": "eval: doc.auth_method === \"Basic\"", + "depends_on": "eval: doc.auth_method === \"Basic\" && doc.service != \"Frappe Mail\"", "fieldname": "awaiting_password", "fieldtype": "Check", "hide_days": 1, @@ -133,7 +133,7 @@ }, { "default": "0", - "depends_on": "eval: doc.auth_method === \"Basic\"", + "depends_on": "eval: doc.auth_method === \"Basic\" && doc.service != \"Frappe Mail\"", "fieldname": "ascii_encode_password", "fieldtype": "Check", "hide_days": 1, @@ -543,7 +543,6 @@ "label": "Brand Logo" }, { - "depends_on": "eval: doc.service != \"Frappe Mail\"", "fieldname": "authentication_column", "fieldtype": "Section Break", "label": "Authentication" @@ -634,28 +633,6 @@ "fieldtype": "Tab Break", "label": "Incoming" }, - { - "fieldname": "api_key", - "fieldtype": "Data", - "label": "API Key", - "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\"" - }, - { - "fieldname": "api_secret", - "fieldtype": "Password", - "label": "API Secret", - "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\"" - }, - { - "depends_on": "eval: doc.service == \"Frappe Mail\"", - "fieldname": "authentication_section", - "fieldtype": "Section Break", - "label": "Authentication" - }, - { - "fieldname": "column_break_ghqa", - "fieldtype": "Column Break" - }, { "default": "https://frappemail.com", "depends_on": "eval: doc.service == \"Frappe Mail\"", @@ -687,12 +664,32 @@ "fieldname": "last_synced_at", "fieldtype": "Datetime", "label": "Last Synced At" + }, + { + "depends_on": "eval: (doc.service == \"Frappe Mail\" && doc.auth_method != \"Basic\" && !doc.__islocal && !doc.__unsaved)", + "fieldname": "validate_frappe_mail_settings", + "fieldtype": "Button", + "label": "Validate Frappe Mail Settings" + }, + { + "depends_on": "eval: doc.service == \"Frappe Mail\" && doc.auth_method == \"Basic\"", + "fieldname": "api_key", + "fieldtype": "Data", + "label": "API Key", + "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\" && doc.auth_method == \"Basic\"" + }, + { + "depends_on": "eval: doc.service == \"Frappe Mail\" && doc.auth_method == \"Basic\"", + "fieldname": "api_secret", + "fieldtype": "Password", + "label": "API Secret", + "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\" && doc.auth_method == \"Basic\"" } ], "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-22 08:51:12.977896", + "modified": "2024-06-28 08:45:43.565934", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index cd4cf4d11a..b5ba3bc216 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -135,22 +135,19 @@ class EmailAccount(Document): if self.email_id: validate_email_address(self.email_id, True) - if self.service == "Frappe Mail": - if self.use_imap: - self.use_imap = 0 - - if not self.always_use_account_email_id_as_sender: - self.always_use_account_email_id_as_sender = 1 - - frappe_mail_client = self.get_frappe_mail_client() - frappe_mail_client.validate(for_inbound=self.enable_incoming, for_outbound=self.enable_outgoing) - if self.login_id_is_different: if not self.login_id: frappe.throw(_("Login Id is required")) else: self.login_id = None + if self.service == "Frappe Mail": + self.use_imap = 0 + self.always_use_account_email_id_as_sender = 1 + + if self.auth_method == "Basic" or self.get_oauth_token(): + self.validate_frappe_mail_settings() + # validate the imap settings if self.enable_incoming and self.use_imap and len(self.imap_folder) <= 0: frappe.throw(_("You need to set one IMAP folder for {0}").format(frappe.bold(self.email_id))) @@ -197,6 +194,12 @@ class EmailAccount(Document): if folder.append_to not in valid_doctypes: frappe.throw(_("Append To can be one of {0}").format(comma_or(valid_doctypes))) + @frappe.whitelist() + def validate_frappe_mail_settings(self): + if self.service == "Frappe Mail": + frappe_mail_client = self.get_frappe_mail_client() + frappe_mail_client.validate(for_inbound=self.enable_incoming, for_outbound=self.enable_outgoing) + def validate_smtp_conn(self): if not self.smtp_server: frappe.throw(_("SMTP Server is required")) @@ -489,9 +492,11 @@ class EmailAccount(Document): return account_details - def sendmail_config(self): + def get_access_token(self) -> str | None: oauth_token = self.get_oauth_token() + return oauth_token.get_password("access_token") if oauth_token else None + def sendmail_config(self): return { "email_account": self.name, "server": self.smtp_server, @@ -501,7 +506,7 @@ class EmailAccount(Document): "use_ssl": cint(self.use_ssl_for_outgoing), "use_tls": cint(self.use_tls), "use_oauth": self.auth_method == "OAuth", - "access_token": oauth_token.get_password("access_token") if oauth_token else None, + "access_token": self.get_access_token(), } def get_smtp_server(self): @@ -522,7 +527,20 @@ class EmailAccount(Document): @functools.cached_property def _frappe_mail_client(self): - return FrappeMail(self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret")) + if self.auth_method == "OAuth": + if access_token := self.get_access_token(): + return FrappeMail(self.frappe_mail_site, self.email_id, access_token=access_token) + + frappe.throw( + _("Please Authorize OAuth for Email Account {0}").format( + frappe.bold(self.email_account_name) + ), + title=_("Frappe Mail OAuth Error"), + ) + else: + return FrappeMail( + self.frappe_mail_site, self.email_id, self.api_key, self.get_password("api_secret") + ) def remove_unpicklable_values(self, state): super().remove_unpicklable_values(state) @@ -617,7 +635,7 @@ class EmailAccount(Document): try: if self.service == "Frappe Mail": frappe_mail_client = self.get_frappe_mail_client() - messages = frappe_mail_client.pull(last_synced_at=self.last_synced_at) + messages = frappe_mail_client.pull_raw(last_synced_at=self.last_synced_at) process_mail(messages) self.db_set("last_synced_at", messages["last_synced_at"], update_modified=False) else: diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index 0ffea902e2..e6b3f2e62c 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -14,6 +14,7 @@ from frappe.core.utils import html2text from frappe.database.database import savepoint from frappe.email.doctype.email_account.email_account import EmailAccount from frappe.email.email_body import add_attachment, get_email, get_formatted_html +from frappe.email.frappemail import FrappeMail from frappe.email.queue import get_unsubcribed_url, get_unsubscribe_message from frappe.email.smtp import SMTPServer from frappe.model.document import Document @@ -153,12 +154,12 @@ class EmailQueue(Document): return True - def send(self, smtp_server_instance: SMTPServer = None): + def send(self, smtp_server_instance: SMTPServer = None, frappe_mail_client: FrappeMail = None): """Send emails to recipients.""" if not self.can_send_now(): return - with SendMailContext(self, smtp_server_instance) as ctx: + with SendMailContext(self, smtp_server_instance, frappe_mail_client) as ctx: ctx.fetch_outgoing_server() message = None for recipient in self.recipients: @@ -170,7 +171,7 @@ class EmailQueue(Document): method(self, self.sender, recipient.recipient, message) elif not frappe.flags.in_test or frappe.flags.testing_email: if ctx.email_account_doc.service == "Frappe Mail": - ctx.frappe_mail_client.send( + ctx.frappe_mail_client.send_raw( sender=self.sender, recipients=recipient.recipient, message=message.decode("utf-8"), @@ -237,9 +238,11 @@ class SendMailContext: self, queue_doc: Document, smtp_server_instance: SMTPServer = None, + frappe_mail_client: FrappeMail = None, ): self.queue_doc: EmailQueue = queue_doc self.smtp_server: SMTPServer = smtp_server_instance + self.frappe_mail_client: FrappeMail = frappe_mail_client self.sent_to_atleast_one_recipient = any( rec.recipient for rec in self.queue_doc.recipients if rec.is_mail_sent() ) @@ -248,7 +251,8 @@ class SendMailContext: self.email_account_doc = self.queue_doc.get_email_account(raise_error=True) if self.email_account_doc.service == "Frappe Mail": - self.frappe_mail_client = self.email_account_doc.get_frappe_mail_client() + if not self.frappe_mail_client: + self.frappe_mail_client = self.email_account_doc.get_frappe_mail_client() elif not self.smtp_server: self.smtp_server = self.email_account_doc.get_smtp_server() @@ -755,16 +759,21 @@ class QueueBuilder: def send_emails(self, queue_data, final_recipients): # This is used to bulk send emails from same sender to multiple recipients separately # This re-uses smtp server instance to minimize the cost of new session creation + frappe_mail_client = None smtp_server_instance = None for r in final_recipients: recipients = list(set([r, *self.final_cc(), *self.bcc])) q = EmailQueue.new({**queue_data, **{"recipients": recipients}}, ignore_permissions=True) - if not smtp_server_instance: + if not frappe_mail_client and not smtp_server_instance: email_account = q.get_email_account(raise_error=True) - smtp_server_instance = email_account.get_smtp_server() + + if email_account.service == "Frappe Mail": + frappe_mail_client = email_account.get_frappe_mail_client() + else: + smtp_server_instance = email_account.get_smtp_server() with suppress(Exception): - q.send(smtp_server_instance=smtp_server_instance) + q.send(smtp_server_instance=smtp_server_instance, frappe_mail_client=frappe_mail_client) smtp_server_instance.quit() diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index ecec7e0564..e9d792aae6 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -5,33 +5,40 @@ from urllib.parse import urljoin import pytz import frappe -from frappe.frappeclient import FrappeClient +from frappe import _ +from frappe.frappeclient import FrappeClient, FrappeOAuth2Client from frappe.utils import convert_utc_to_system_timezone, get_datetime, get_datetime_str, get_system_timezone if TYPE_CHECKING: from requests import Response -class FrappeMailException(Exception): - """Exception raised for errors in the Frappe Mail API.""" - - def __init__(self, message: str, status_code: int) -> None: - self.message = message - self.status_code = status_code - super().__init__(message) - - class FrappeMail: """Class to interact with the Frappe Mail API.""" - def __init__(self, site: str, mailbox: str, api_key: str, api_secret: str) -> None: + def __init__( + self, + site: str, + mailbox: str, + api_key: str | None = None, + api_secret: str | None = None, + access_token: str | None = None, + ) -> None: self.site = site self.mailbox = mailbox - self.client = self.get_client(site, mailbox, api_key, api_secret) + self.api_key = api_key + self.api_secret = api_secret + self.access_token = access_token @staticmethod - def get_client(site: str, mailbox: str, api_key: str, api_secret: str) -> "FrappeClient": - """Returns a FrappeClient instance.""" + def get_client( + site: str, + mailbox: str, + api_key: str | None = None, + api_secret: str | None = None, + access_token: str | None = None, + ) -> FrappeClient | FrappeOAuth2Client: + """Returns a FrappeClient or FrappeOAuth2Client instance.""" if hasattr(frappe.local, "frappe_mail_clients"): if client := frappe.local.frappe_mail_clients.get(mailbox): @@ -39,7 +46,11 @@ class FrappeMail: else: frappe.local.frappe_mail_clients = {} - client = FrappeClient(url=site, api_key=api_key, api_secret=api_secret) + client = ( + FrappeOAuth2Client(url=site, access_token=access_token) + if access_token + else FrappeClient(url=site, api_key=api_key, api_secret=api_secret) + ) frappe.local.frappe_mail_clients[mailbox] = client return client @@ -58,14 +69,26 @@ class FrappeMail: """Makes a HTTP request to the Frappe Mail API.""" url = urljoin(self.site, endpoint) + client = self.get_client(self.site, self.mailbox, self.api_key, self.api_secret, self.access_token) + headers = headers or {} - headers.update(self.client.headers) - response = self.client.session.request( + headers.update(client.headers) + + response = client.session.request( method=method, url=url, params=params, data=data, json=json, headers=headers, timeout=timeout ) if not response.ok and raise_exception: - raise FrappeMailException(response.text, response.status_code) + error_msg = response.text + if response.status_code == 401: + if self.access_token: + error_msg = _("Authentication Error: Reauthorize OAuth for Email Account {0}.").format( + frappe.bold(self.mailbox) + ) + else: + error_msg = _("Authentication Error: Invalid API Key or Secret") + + frappe.throw(title=_("Frappe Mail"), msg=error_msg) return response @@ -77,20 +100,20 @@ class FrappeMail: response = self.request("POST", endpoint=endpoint, data=data, raise_exception=False) if not response.ok: - if exception := response.json().get("exception"): - if exception == "frappe.exceptions.AuthenticationError": - exception += ": Invalid API Key or Secret" + if error_msg := response.json().get("exception"): + if error_msg == "frappe.exceptions.AuthenticationError": + error_msg += ": Invalid API Key or Secret" - frappe.throw(title="Frappe Mail", msg=exception) + frappe.throw(title="Frappe Mail", msg=error_msg) - def send(self, sender: str, recipients: str, message: str) -> None: + def send_raw(self, sender: str, recipients: str, message: str) -> None: """Sends an email using the Frappe Mail API.""" endpoint = "outbound/send-raw" json_data = {"from": sender, "to": recipients, "raw_message": message} self.request("POST", endpoint=endpoint, json=json_data) - def pull(self, limit: int = 50, last_synced_at: str | None = None) -> dict[str, list[str] | str]: + def pull_raw(self, limit: int = 50, last_synced_at: str | None = None) -> dict[str, list[str] | str]: """Pulls emails from the mailbox using the Frappe Mail API.""" endpoint = "inbound/pull-raw" From fa4131a458084b776eeb6f57ac1c650ec4ac5575 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Tue, 2 Jul 2024 06:35:53 +0200 Subject: [PATCH 023/176] fix: frappe/core/doctype/doctype/doctype.js Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com> --- frappe/core/doctype/doctype/doctype.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.js b/frappe/core/doctype/doctype/doctype.js index 8ff8b8a9c0..6cfb54dc1c 100644 --- a/frappe/core/doctype/doctype/doctype.js +++ b/frappe/core/doctype/doctype/doctype.js @@ -62,7 +62,7 @@ frappe.ui.form.on("DocType", { } } - const customize_form_link = "__(Customize Form)"; + const customize_form_link = `${__("Customize Form")}`; if (!frappe.boot.developer_mode && !frm.doc.custom) { // make the document read-only frm.set_read_only(); From 8b80a89036ea98fc2830cc8294256b22e1fff378 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Tue, 2 Jul 2024 06:38:33 +0200 Subject: [PATCH 024/176] fix: frappe/public/js/frappe/utils/dashboard_utils.js Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com> --- frappe/public/js/frappe/utils/dashboard_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/utils/dashboard_utils.js b/frappe/public/js/frappe/utils/dashboard_utils.js index 89c53ee0ff..2ad0dcc2cb 100644 --- a/frappe/public/js/frappe/utils/dashboard_utils.js +++ b/frappe/public/js/frappe/utils/dashboard_utils.js @@ -162,7 +162,7 @@ frappe.dashboard_utils = { options: `

${__("Set dynamic filter values in JavaScript for the required fields here.")}

-

Ex: +

${__("For example:")} frappe.defaults.get_user_default("Company")

`, From 442ad03d7b80ed4ad292ec4e31eb5090865e7570 Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Thu, 4 Jul 2024 19:09:27 +0200 Subject: [PATCH 025/176] feat: Adds possibility of permitting DB credentials via ENV vars instead of persisting them on the volume. --- frappe/__init__.py | 22 ++++++++++++++-------- frappe/tests/test_db.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 6357da0a68..e5b013b3e2 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -339,17 +339,23 @@ def connect(site: str | None = None, db_name: str | None = None, set_admin_as_us "Instead, explicitly invoke frappe.init(site) with the right config prior to calling frappe.connect(), if necessary." ) - assert db_name or local.conf.db_user, "site must be fully initialized, db_user missing" - assert db_name or local.conf.db_name, "site must be fully initialized, db_name missing" - assert local.conf.db_password, "site must be fully initialized, db_password missing" + db_name = db_name or os.getenv('DB_NAME') or local.conf.db_name or local.conf.db_user + user = os.getenv('DB_USER') or local.conf.db_user or db_name + host = os.getenv('DB_HOST') or local.conf.db_host + port = os.getenv('DB_PORT') or local.conf.db_port + password = os.getenv('DB_PASSWORD') or local.conf.db_password + + assert user, "site must be fully initialized, db_user missing" + assert db_name, "site must be fully initialized, db_name missing" + assert password, "site must be fully initialized, db_password missing" local.db = get_db( socket=local.conf.db_socket, - host=local.conf.db_host, - port=local.conf.db_port, - user=local.conf.db_user or db_name, - password=local.conf.db_password, - cur_db_name=local.conf.db_name or db_name, + host=host, + port=port, + user=user, + password=password, + cur_db_name=db_name, ) if set_admin_as_user: set_user("Administrator") diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 715522d868..01198ecb38 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1079,3 +1079,42 @@ class TestSqlIterator(FrappeTestCase): def test_unbuffered_cursor(self): with frappe.db.unbuffered_cursor(): self.test_db_sql_iterator() + + +class TestDbConnectWithEnvCredentials(FrappeTestCase): + def test_connect_fails_with_wrong_credentials_by_env(self) -> None: + import os + + # with wrong db name + os.environ["DB_NAME"] = "dbiq" + + frappe.connect() + self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + + # with wrong host + del os.environ["DB_NAME"] + os.environ["DB_HOST"] = "iqx.local" + + frappe.connect() + self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + + # with wrong user name + del os.environ["DB_HOST"] + os.environ["DB_USER"] = "uname" + + frappe.connect() + self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + + # with wrong password + del os.environ["DB_USER"] + os.environ["DB_PASSWORD"] = "pass" + + frappe.connect() + self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + + # now with configured settings without any influences from env + del os.environ["DB_PASSWORD"] + + # finally connect should work without any error (when no wrong credentials are given via ENV) + frappe.connect() + frappe.db.connect() From a63cd89607db09eb1cccdddbd28d370a3155eaad Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Thu, 4 Jul 2024 22:05:39 +0200 Subject: [PATCH 026/176] fix: Fixed wrong quotes for changes --- frappe/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index e5b013b3e2..edd17bfe7b 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -339,11 +339,11 @@ def connect(site: str | None = None, db_name: str | None = None, set_admin_as_us "Instead, explicitly invoke frappe.init(site) with the right config prior to calling frappe.connect(), if necessary." ) - db_name = db_name or os.getenv('DB_NAME') or local.conf.db_name or local.conf.db_user - user = os.getenv('DB_USER') or local.conf.db_user or db_name - host = os.getenv('DB_HOST') or local.conf.db_host - port = os.getenv('DB_PORT') or local.conf.db_port - password = os.getenv('DB_PASSWORD') or local.conf.db_password + db_name = db_name or os.getenv("DB_NAME") or local.conf.db_name or local.conf.db_user + user = os.getenv("DB_USER") or local.conf.db_user or db_name + host = os.getenv("DB_HOST") or local.conf.db_host + port = os.getenv("DB_PORT") or local.conf.db_port + password = os.getenv("DB_PASSWORD") or local.conf.db_password assert user, "site must be fully initialized, db_user missing" assert db_name, "site must be fully initialized, db_name missing" From afd95691e9448f24279abd51ea4c3f38cd24b4ae Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Thu, 4 Jul 2024 19:10:34 +0200 Subject: [PATCH 027/176] fix: Fixed schema isolation/support for postgres connectivity. --- frappe/database/postgres/database.py | 56 +++++++-- frappe/tests/test_db.py | 168 +++++++++++++++++++++++++++ 2 files changed, 214 insertions(+), 10 deletions(-) diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index 7bae004986..e7a15c72ff 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -20,6 +20,7 @@ from psycopg2.errors import ( SyntaxError, ) from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ +from psycopg2 import sql import frappe from frappe.database.database import Database @@ -169,6 +170,15 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def last_query(self): return LazyDecode(self._cursor.query) + @property + def db_schema(self): + return re.sub(r'["\']', '', frappe.conf.get("db_schema", "public")) + + def connect(self): + super().connect() + + self._cursor.execute("SET search_path TO %s", (self.db_schema,)) + def get_connection(self): conn_settings = { "dbname": self.cur_db_name, @@ -228,12 +238,30 @@ class PostgresDatabase(PostgresExceptionUtil, Database): for d in self.sql( """select table_name from information_schema.tables - where table_catalog='{}' + where table_catalog=%s and table_type = 'BASE TABLE' - and table_schema='{}'""".format(self.cur_db_name, frappe.conf.get("db_schema", "public")) + and table_schema=%s""", (self.cur_db_name, self.db_schema) ) ] + def get_db_table_columns(self, table) -> list[str]: + """Returns list of column names from given table.""" + columns = frappe.cache.hget("table_columns", table) + if columns is None: + information_schema = frappe.qb.Schema("information_schema") + + columns = ( + frappe.qb.from_(information_schema.columns) + .select(information_schema.columns.column_name) + .where((information_schema.columns.table_name == table) & (information_schema.columns.table_schema == self.db_schema)) + .run(pluck=True) + ) + + if columns: + frappe.cache.hset("table_columns", table, columns) + + return columns + def format_date(self, date): if not date: return "0001-01-01" @@ -260,7 +288,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def describe(self, doctype: str) -> list | tuple: table_name = get_table_name(doctype) return self.sql( - f"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = '{table_name}'" + f"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = '{table_name}' and table_schema='{frappe.conf.get('db_schema', 'public')}'" ) def change_column_type( @@ -349,8 +377,9 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def has_index(self, table_name, index_name): return self.sql( - f"""SELECT 1 FROM pg_indexes WHERE tablename='{table_name}' - and indexname='{index_name}' limit 1""" + """SELECT 1 FROM pg_indexes WHERE tablename=%s + and schemaname = %s + and indexname=%s limit 1""", (table_name, self.db_schema, index_name) ) def add_index(self, doctype: str, fields: list, index_name: str | None = None): @@ -360,7 +389,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): index_name = index_name or self.get_index_name(fields) fields_str = '", "'.join(re.sub(r"\(.*\)", "", field) for field in fields) - self.sql_ddl(f'CREATE INDEX IF NOT EXISTS "{index_name}" ON `{table_name}` ("{fields_str}")') + self.sql_ddl(f'CREATE INDEX IF NOT EXISTS "{index_name}" ON "{self.db_schema}"."{table_name}" ("{fields_str}")') def add_unique(self, doctype, fields, constraint_name=None): if isinstance(fields, str): @@ -374,13 +403,18 @@ class PostgresDatabase(PostgresExceptionUtil, Database): FROM information_schema.TABLE_CONSTRAINTS WHERE table_name=%s AND constraint_type='UNIQUE' + AND constraint_schema=%s AND CONSTRAINT_NAME=%s""", - ("tab" + doctype, constraint_name), + ("tab" + doctype, self.db_schema, constraint_name), ): self.commit() + self.sql( - """ALTER TABLE `tab{}` - ADD CONSTRAINT {} UNIQUE ({})""".format(doctype, constraint_name, ", ".join(fields)) + sql.SQL("""ALTER TABLE {schema}.{table} + ADD CONSTRAINT {constraint} UNIQUE ({fields})""").format(schema=sql.Identifier(self.db_schema), + table=sql.Identifier('tab' + doctype), + constraint=sql.Identifier(constraint_name), + fields=sql.SQL(', ').join(map(sql.Identifier, fields))).as_string(self._conn) ) def get_table_columns_description(self, table_name): @@ -404,9 +438,10 @@ class PostgresDatabase(PostgresExceptionUtil, Database): indexdef LIKE '%UNIQUE INDEX%' AS unique, indexdef NOT LIKE '%UNIQUE INDEX%' AS index FROM pg_indexes - WHERE tablename='{table_name}') b + WHERE tablename='{table_name}' AND schemaname='{self.db_schema}') b ON SUBSTRING(b.indexdef, '(.*)') LIKE CONCAT('%', a.column_name, '%') WHERE a.table_name = '{table_name}' + AND a.table_schema = '{self.db_schema}' GROUP BY a.column_name, a.data_type, a.column_default, a.character_maximum_length, a.is_nullable; """, as_dict=1, @@ -423,6 +458,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): .where( (information_schema.columns.table_name == table) & (information_schema.columns.column_name == column) + & (information_schema.columns.table_schema == self.db_schema) ) .run(pluck=True)[0] ) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 715522d868..77470b153b 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1079,3 +1079,171 @@ class TestSqlIterator(FrappeTestCase): def test_unbuffered_cursor(self): with frappe.db.unbuffered_cursor(): self.test_db_sql_iterator() + +class ExtFrappeTestCase(FrappeTestCase): + def assertSqlException(self): + class SqlExceptionContextManager: + def __init__(self, test_case): + self.test_case = test_case + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is None: + self.test_case.fail("Expected exception but none was raised") + else: + frappe.db.rollback() + # Returning True suppresses the exception + return True + + return SqlExceptionContextManager(self) + +@run_only_if(db_type_is.POSTGRES) +class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): + test_table_name = "TestSchemaTable" + + def setUp(self, rollback=False) -> None: + if rollback: + frappe.db.rollback() + + + if frappe.db.sql("""SELECT 1 + FROM information_schema.schemata + WHERE schema_name = 'alt_schema' + limit 1 """): + self.cleanup() + + frappe.db.sql( + f""" + CREATE SCHEMA alt_schema; + + CREATE TABLE "public"."tab{self.test_table_name}" ( + col_a VARCHAR, + col_b VARCHAR + ); + + CREATE TABLE "alt_schema"."tab{self.test_table_name}" ( + col_c VARCHAR PRIMARY KEY, + col_d VARCHAR + ); + + CREATE TABLE "alt_schema"."tab{self.test_table_name}_2" ( + col_c VARCHAR, + col_d VARCHAR + ); + + CREATE TABLE "alt_schema"."tabUser" ( + col_c VARCHAR, + col_d VARCHAR + ); + + insert into "public"."tab{self.test_table_name}" (col_a, col_b) values ('a', 'b'); + """ + ) + + def tearDown(self) -> None: + self.cleanup() + + def cleanup(self) -> None: + frappe.db.sql(f""" + DROP TABLE "public"."tab{self.test_table_name}"; + DROP TABLE "alt_schema"."tab{self.test_table_name}"; + DROP TABLE "alt_schema"."tab{self.test_table_name}_2"; + DROP TABLE "alt_schema"."tabUser"; + DROP SCHEMA "alt_schema" CASCADE; + """) + # DROP USER u_alt_schema; + + def test_get_tables(self) -> None: + tables = frappe.db.get_tables(cached=False) + + # should have received the table {test_table_name} only once (from public schema) + count = sum([1 for table in tables if f"tab{self.test_table_name}" in table]) + self.assertEqual(count, 1) + + # should not have received {test_table_name}_2, as selection should only be from public schema + self.assertNotIn(f"tab{self.test_table_name}_2", tables) + + def test_db_table_columns(self) -> None: + columns = frappe.db.get_table_columns(self.test_table_name) + + # should have received the columns of the table from public schema + self.assertEqual(columns, ["col_a", "col_b"]) + + frappe.conf["db_schema"] = "alt_schema" + frappe.cache.delete_key("table_columns") # remove table columns cache for next try from alt_schema + + # should have received the columns of the table from alt_schema + columns = frappe.db.get_table_columns(self.test_table_name) + self.assertEqual(columns, ["col_c", "col_d"]) + + del frappe.conf["db_schema"] + frappe.cache.delete_key("table_columns") + + def test_describe(self) -> None: + self.assertSequenceEqual([("col_a",), ("col_b",)], frappe.db.describe(self.test_table_name)) + + def test_has_index(self) -> None: + # should not find any index on the table in default public schema (as it is only in the alt_schema) + self.assertFalse(frappe.db.has_index(f"tab{self.test_table_name}", f"tab{self.test_table_name}_pkey")) + + def test_add_index(self) -> None: + frappe.conf["db_schema"] = "alt_schema" + + # only dummy tabUser table in alt_schema has "col_c" column + frappe.db.add_index("User", ("col_c",)) + + del frappe.conf["db_schema"] + frappe.cache.delete_key("table_columns") + + # the index creation in the default schema should fail + with self.assertSqlException(): + frappe.db.add_index(doctype="User", fields=("col_c",)) + + # TODO: is there some method like remove_index: + # TODO: apps/frappe/frappe/patches/v14_0/drop_unused_indexes.py # def drop_index_if_exists() + # TODO: apps/frappe/frappe/database/postgres/schema.py # def alter() + + def test_add_unique(self) -> None: + # should fail to add a unique constraint on the table in default public schema with those columns which are only present in alt_schema + with self.assertSqlException(): + frappe.db.add_unique(f"{self.test_table_name}", ["col_c", "col_d"]) + + # but should work if the schema is configured to alt_schema + frappe.conf["db_schema"] = "alt_schema" + + # should have received the columns of the table from alt_schema + frappe.db.add_unique(f"{self.test_table_name}", ["col_c", "col_d"]) + + del frappe.conf["db_schema"] + + def test_get_table_columns_description(self): + # should only return the columns of the table in the default public schema + columns = frappe.db.get_table_columns_description(f'tab{self.test_table_name}') + + self.assertTrue(any([col for col in columns if col["name"] == "col_a"])) + self.assertTrue(any([col for col in columns if col["name"] == "col_b"])) + self.assertFalse(any([col for col in columns if col["name"] == "col_c"])) + self.assertFalse(any([col for col in columns if col["name"] == "col_d"])) + + def test_get_column_type(self): + # should return the column type of the column in the default public schema + self.assertEqual(frappe.db.get_column_type(self.test_table_name, "col_a"), "character varying") + + # should raise an error for the column in the alt_schema + with self.assertSqlException(): + frappe.db.get_column_type(self.test_table_name, "col_c") + + def test_search_path(self): + # by default the the public schema tables should be addressed by search path + rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') + self.assertEqual(rows, [("a", "b",)]) # there should be a single row in the public table + + # when schema is changed to alt_schema, the alt_schema tables should be addressed by search path + frappe.conf["db_schema"] = "alt_schema" + frappe.db.connect() + rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') + self.assertEqual(rows, []) # there are no records in the alt_schema table + + del frappe.conf["db_schema"] From d3591c71701c30a85156f5771706aef8755623eb Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Thu, 4 Jul 2024 23:05:44 +0200 Subject: [PATCH 028/176] fix: Added missing ruff adjustments --- frappe/database/postgres/database.py | 35 +++++++++++++++-------- frappe/tests/test_db.py | 42 ++++++++++++++++++---------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index e7a15c72ff..c3a69473ee 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -2,6 +2,7 @@ import re import psycopg2 import psycopg2.extensions +from psycopg2 import sql from psycopg2.errorcodes import ( CLASS_INTEGRITY_CONSTRAINT_VIOLATION, DEADLOCK_DETECTED, @@ -20,7 +21,6 @@ from psycopg2.errors import ( SyntaxError, ) from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ -from psycopg2 import sql import frappe from frappe.database.database import Database @@ -172,7 +172,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): @property def db_schema(self): - return re.sub(r'["\']', '', frappe.conf.get("db_schema", "public")) + return re.sub(r'["\']', "", frappe.conf.get("db_schema", "public")) def connect(self): super().connect() @@ -240,7 +240,8 @@ class PostgresDatabase(PostgresExceptionUtil, Database): from information_schema.tables where table_catalog=%s and table_type = 'BASE TABLE' - and table_schema=%s""", (self.cur_db_name, self.db_schema) + and table_schema=%s""", + (self.cur_db_name, self.db_schema), ) ] @@ -253,7 +254,10 @@ class PostgresDatabase(PostgresExceptionUtil, Database): columns = ( frappe.qb.from_(information_schema.columns) .select(information_schema.columns.column_name) - .where((information_schema.columns.table_name == table) & (information_schema.columns.table_schema == self.db_schema)) + .where( + (information_schema.columns.table_name == table) + & (information_schema.columns.table_schema == self.db_schema) + ) .run(pluck=True) ) @@ -379,7 +383,8 @@ class PostgresDatabase(PostgresExceptionUtil, Database): return self.sql( """SELECT 1 FROM pg_indexes WHERE tablename=%s and schemaname = %s - and indexname=%s limit 1""", (table_name, self.db_schema, index_name) + and indexname=%s limit 1""", + (table_name, self.db_schema, index_name), ) def add_index(self, doctype: str, fields: list, index_name: str | None = None): @@ -389,7 +394,9 @@ class PostgresDatabase(PostgresExceptionUtil, Database): index_name = index_name or self.get_index_name(fields) fields_str = '", "'.join(re.sub(r"\(.*\)", "", field) for field in fields) - self.sql_ddl(f'CREATE INDEX IF NOT EXISTS "{index_name}" ON "{self.db_schema}"."{table_name}" ("{fields_str}")') + self.sql_ddl( + f'CREATE INDEX IF NOT EXISTS "{index_name}" ON "{self.db_schema}"."{table_name}" ("{fields_str}")' + ) def add_unique(self, doctype, fields, constraint_name=None): if isinstance(fields, str): @@ -410,11 +417,17 @@ class PostgresDatabase(PostgresExceptionUtil, Database): self.commit() self.sql( - sql.SQL("""ALTER TABLE {schema}.{table} - ADD CONSTRAINT {constraint} UNIQUE ({fields})""").format(schema=sql.Identifier(self.db_schema), - table=sql.Identifier('tab' + doctype), - constraint=sql.Identifier(constraint_name), - fields=sql.SQL(', ').join(map(sql.Identifier, fields))).as_string(self._conn) + sql.SQL( + """ALTER TABLE {schema}.{table} + ADD CONSTRAINT {constraint} UNIQUE ({fields})""" + ) + .format( + schema=sql.Identifier(self.db_schema), + table=sql.Identifier("tab" + doctype), + constraint=sql.Identifier(constraint_name), + fields=sql.SQL(", ").join(map(sql.Identifier, fields)), + ) + .as_string(self._conn) ) def get_table_columns_description(self, table_name): diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 77470b153b..2d939f7a72 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1080,6 +1080,7 @@ class TestSqlIterator(FrappeTestCase): with frappe.db.unbuffered_cursor(): self.test_db_sql_iterator() + class ExtFrappeTestCase(FrappeTestCase): def assertSqlException(self): class SqlExceptionContextManager: @@ -1099,6 +1100,7 @@ class ExtFrappeTestCase(FrappeTestCase): return SqlExceptionContextManager(self) + @run_only_if(db_type_is.POSTGRES) class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): test_table_name = "TestSchemaTable" @@ -1107,11 +1109,12 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): if rollback: frappe.db.rollback() - - if frappe.db.sql("""SELECT 1 + if frappe.db.sql( + """SELECT 1 FROM information_schema.schemata WHERE schema_name = 'alt_schema' - limit 1 """): + limit 1 """ + ): self.cleanup() frappe.db.sql( @@ -1146,14 +1149,15 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): self.cleanup() def cleanup(self) -> None: - frappe.db.sql(f""" - DROP TABLE "public"."tab{self.test_table_name}"; - DROP TABLE "alt_schema"."tab{self.test_table_name}"; - DROP TABLE "alt_schema"."tab{self.test_table_name}_2"; - DROP TABLE "alt_schema"."tabUser"; - DROP SCHEMA "alt_schema" CASCADE; - """) - # DROP USER u_alt_schema; + frappe.db.sql( + f""" + DROP TABLE "public"."tab{self.test_table_name}"; + DROP TABLE "alt_schema"."tab{self.test_table_name}"; + DROP TABLE "alt_schema"."tab{self.test_table_name}_2"; + DROP TABLE "alt_schema"."tabUser"; + DROP SCHEMA "alt_schema" CASCADE; + """ + ) def test_get_tables(self) -> None: tables = frappe.db.get_tables(cached=False) @@ -1172,7 +1176,7 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): self.assertEqual(columns, ["col_a", "col_b"]) frappe.conf["db_schema"] = "alt_schema" - frappe.cache.delete_key("table_columns") # remove table columns cache for next try from alt_schema + frappe.cache.delete_key("table_columns") # remove table columns cache for next try from alt_schema # should have received the columns of the table from alt_schema columns = frappe.db.get_table_columns(self.test_table_name) @@ -1220,7 +1224,7 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): def test_get_table_columns_description(self): # should only return the columns of the table in the default public schema - columns = frappe.db.get_table_columns_description(f'tab{self.test_table_name}') + columns = frappe.db.get_table_columns_description(f"tab{self.test_table_name}") self.assertTrue(any([col for col in columns if col["name"] == "col_a"])) self.assertTrue(any([col for col in columns if col["name"] == "col_b"])) @@ -1238,12 +1242,20 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): def test_search_path(self): # by default the the public schema tables should be addressed by search path rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') - self.assertEqual(rows, [("a", "b",)]) # there should be a single row in the public table + self.assertEqual( + rows, + [ + ( + "a", + "b", + ) + ], + ) # there should be a single row in the public table # when schema is changed to alt_schema, the alt_schema tables should be addressed by search path frappe.conf["db_schema"] = "alt_schema" frappe.db.connect() rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') - self.assertEqual(rows, []) # there are no records in the alt_schema table + self.assertEqual(rows, []) # there are no records in the alt_schema table del frappe.conf["db_schema"] From 2e0ca7d3a7f25e094664f63ba6078293f78343fd Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Thu, 4 Jul 2024 23:25:46 +0200 Subject: [PATCH 029/176] fix: simplified functional call to iterator (semgrep) --- frappe/database/postgres/database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index c3a69473ee..caba53e242 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -425,7 +425,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): schema=sql.Identifier(self.db_schema), table=sql.Identifier("tab" + doctype), constraint=sql.Identifier(constraint_name), - fields=sql.SQL(", ").join(map(sql.Identifier, fields)), + fields=sql.SQL(", ").join(sql.Identifier(field) for field in fields), ) .as_string(self._conn) ) From 24886427464fcf3d0ceb8ea6b9c484bb6b17de4b Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 5 Jul 2024 08:26:03 +0530 Subject: [PATCH 030/176] chore: connected app - show title in link field --- frappe/integrations/doctype/connected_app/connected_app.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/integrations/doctype/connected_app/connected_app.json b/frappe/integrations/doctype/connected_app/connected_app.json index 201f161120..9fc63cd520 100644 --- a/frappe/integrations/doctype/connected_app/connected_app.json +++ b/frappe/integrations/doctype/connected_app/connected_app.json @@ -139,7 +139,7 @@ "link_fieldname": "connected_app" } ], - "modified": "2024-03-23 16:01:30.633764", + "modified": "2024-07-05 08:24:50.182706", "modified_by": "Administrator", "module": "Integrations", "name": "Connected App", @@ -162,6 +162,7 @@ "role": "All" } ], + "show_title_field_in_link": 1, "sort_field": "creation", "sort_order": "DESC", "states": [], From d56430da53a528508be282ecf270fa39f42797c4 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 5 Jul 2024 10:42:24 +0200 Subject: [PATCH 031/176] fix: email record linking via rfc5233 & rfc5322 --- .../doctype/communication/communication.py | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 468f7ea6ea..bfda36821e 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -593,47 +593,59 @@ def parse_email(email_strings): When automatic email linking is enabled, an email from email_strings can contain a doctype and docname ie in the format `admin+doctype+docname@example.com` or `admin+doctype=docname@example.com`, the email is parsed and doctype and docname is extracted. + + see: RFC5233 """ for email_string in email_strings: if not email_string: continue for email in email_string.split(","): - email_username = email.split("@", 1)[0] - email_local_parts = email_username.split("+") - docname = doctype = None - if len(email_local_parts) == 3: - doctype = unquote(email_local_parts[1]) - docname = unquote(email_local_parts[2]) + local_part = email.split("@", 1)[0].strip('"') + user, detail = None, None + if "+" in local_part: + user, detail = local_part.split("+", 1) + if "--" in local_part: + detail, user = local_part.rsplit("--", 1) - elif len(email_local_parts) == 2: - document_parts = email_local_parts[1].split("=", 1) - if len(document_parts) != 2: - continue + document_parts = None + if detail and "+" in detail: + document_parts = detail.split("+", 1) + elif detail: + document_parts = detail.split("=", 1) - doctype = unquote(document_parts[0]) - docname = unquote(document_parts[1]) + if not document_parts or not len(document_parts) != 2: + continue - if doctype and docname: - yield doctype, docname + doctype = unquote(document_parts[0]) + docname = unquote(document_parts[1]) + yield doctype, docname def get_email_without_link(email): """Return email address without doctype links. e.g. 'admin@example.com' is returned for email 'admin+doctype+docname@example.com' + + see: RFC5233 """ if not frappe.get_all("Email Account", filters={"enable_automatic_linking": 1}): return email try: _email = email.split("@") - email_id = _email[0].split("+", 1)[0] - email_host = _email[1] + _local_part = _email[0].strip('"') + if "+" in _local_part: + user = _local_part.split("+", 1)[0] + elif "--" in _local_part: + user = _local_part.split("--", 1)[1] + else: + user = _local_part + domain = _email[1] except IndexError: return email - return f"{email_id}@{email_host}" + return f"{user}@{domain}" def update_parent_document_on_communication(doc): From b0c57843c419d27ea7858763c2164ce5c36ea51c Mon Sep 17 00:00:00 2001 From: David Date: Wed, 3 Jul 2024 18:29:55 +0200 Subject: [PATCH 032/176] fix: plus quoting for better mta compatibility --- frappe/core/doctype/communication/communication.py | 12 ++++++------ frappe/desk/form/load.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index bfda36821e..b10a7235e1 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -3,7 +3,7 @@ from collections import Counter from email.utils import getaddresses -from urllib.parse import unquote +from urllib.parse import unquote_plus from bs4 import BeautifulSoup @@ -609,16 +609,16 @@ def parse_email(email_strings): detail, user = local_part.rsplit("--", 1) document_parts = None - if detail and "+" in detail: - document_parts = detail.split("+", 1) - elif detail: + if detail and "=" in detail: document_parts = detail.split("=", 1) + elif detail and "+" in detail: + document_parts = detail.split("+", 1) if not document_parts or not len(document_parts) != 2: continue - doctype = unquote(document_parts[0]) - docname = unquote(document_parts[1]) + doctype = unquote_plus(document_parts[0]) + docname = unquote_plus(document_parts[1]) yield doctype, docname diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 9b01c8ecee..8c79c9977e 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -3,7 +3,7 @@ import json import typing -from urllib.parse import quote +from urllib.parse import quote_plus import frappe import frappe.defaults @@ -384,7 +384,7 @@ def get_document_email(doctype, name): return None email = email.split("@") - return f"{email[0]}+{quote(doctype)}={quote(cstr(name))}@{email[1]}" + return f"{email[0]}+{quote_plus(doctype)}={quote_plus(cstr(name))}@{email[1]}" def get_automatic_email_link(): From abba28be3b1b2fdb2010dcdc07ecc6556d32a71b Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Fri, 5 Jul 2024 12:02:04 +0200 Subject: [PATCH 033/176] feat: Added env db options for db, password and pg_schema --- frappe/__init__.py | 31 +++++++++------- frappe/tests/test_db.py | 81 +++++++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 72616ee4c9..e911d538e7 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -339,23 +339,17 @@ def connect(site: str | None = None, db_name: str | None = None, set_admin_as_us "Instead, explicitly invoke frappe.init(site) with the right config prior to calling frappe.connect(), if necessary." ) - db_name = db_name or os.getenv("DB_NAME") or local.conf.db_name or local.conf.db_user - user = os.getenv("DB_USER") or local.conf.db_user or db_name - host = os.getenv("DB_HOST") or local.conf.db_host - port = os.getenv("DB_PORT") or local.conf.db_port - password = os.getenv("DB_PASSWORD") or local.conf.db_password - - assert user, "site must be fully initialized, db_user missing" - assert db_name, "site must be fully initialized, db_name missing" - assert password, "site must be fully initialized, db_password missing" + assert db_name or local.conf.db_user, "site must be fully initialized, db_user missing" + assert db_name or local.conf.db_name, "site must be fully initialized, db_name missing" + assert local.conf.db_password, "site must be fully initialized, db_password missing" local.db = get_db( socket=local.conf.db_socket, - host=host, - port=port, - user=user, - password=password, - cur_db_name=db_name, + host=local.conf.db_host, + port=local.conf.db_port, + user=local.conf.db_user or db_name, + password=local.conf.db_password, + cur_db_name=local.conf.db_name or db_name, ) if set_admin_as_user: set_user("Administrator") @@ -448,6 +442,15 @@ def get_site_config(sites_path: str | None = None, site_path: str | None = None) # Set the user as database name if not set in config config["db_user"] = os.environ.get("FRAPPE_DB_USER") or config.get("db_user") or config.get("db_name") + # vice versa for dbname if not defined + config["db_name"] = os.environ.get("FRAPPE_DB_NAME") or config.get("db_name") or config["db_user"] + + # read password + config["db_password"] = os.environ.get("FRAPPE_DB_PASSWORD") or config.get("db_password") + + if config["db_type"] == "postgres": + config["db_schema"] = os.environ.get("FRAPPE_DB_PG_SCHEMA") or config.get("db_schema") + # Allow externally extending the config with hooks if extra_config := config.get("extra_config"): if isinstance(extra_config, str): diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 01198ecb38..6ba0bb5ce2 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1083,38 +1083,81 @@ class TestSqlIterator(FrappeTestCase): class TestDbConnectWithEnvCredentials(FrappeTestCase): def test_connect_fails_with_wrong_credentials_by_env(self) -> None: + import contextlib import os - # with wrong db name - os.environ["DB_NAME"] = "dbiq" + @contextlib.contextmanager + def set_env_variable(key, value): + os.environ[key] = value + try: + yield + finally: + del os.environ[key] - frappe.connect() - self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + current_site = frappe.local.site + + # with wrong db name + with set_env_variable("FRAPPE_DB_NAME", "dbiq"): + frappe.init(current_site, force=True) + frappe.connect() + + with self.assertRaises(Exception) as cm: + frappe.db.connect() + + self.assertTrue('database "dbiq"' in str(cm.exception)) # with wrong host - del os.environ["DB_NAME"] - os.environ["DB_HOST"] = "iqx.local" + with set_env_variable("FRAPPE_DB_HOST", "iqx.local"): + frappe.init(current_site, force=True) + frappe.connect() - frappe.connect() - self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + with self.assertRaises(Exception) as cm: + frappe.db.connect() + + self.assertTrue('host name "iqx.local"' in str(cm.exception)) # with wrong user name - del os.environ["DB_HOST"] - os.environ["DB_USER"] = "uname" + with set_env_variable("FRAPPE_DB_USER", "uname"): + frappe.init(current_site, force=True) + frappe.connect() - frappe.connect() - self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + with self.assertRaises(Exception) as cm: + frappe.db.connect() + + self.assertTrue('user "uname"' in str(cm.exception)) # with wrong password - del os.environ["DB_USER"] - os.environ["DB_PASSWORD"] = "pass" + with set_env_variable("FRAPPE_DB_PASSWORD", "pass"): + frappe.init(current_site, force=True) + frappe.connect() - frappe.connect() - self.assertRaises(frappe.db.OperationalError, frappe.db.connect) + with self.assertRaises(Exception) as cm: + frappe.db.connect() + + self.assertTrue("password authentication failed" in str(cm.exception)) + + # with wrong password + with set_env_variable("FRAPPE_DB_PORT", "1111"): + frappe.init(current_site, force=True) + frappe.connect() + + with self.assertRaises(Exception) as cm: + frappe.db.connect() + + self.assertTrue("port 1111" in str(cm.exception)) + + # with wrong postgres schema + with set_env_variable("FRAPPE_DB_PG_SCHEMA", "pg_schema"): + frappe.init(current_site, force=True) + frappe.connect() + + if frappe.conf.get("db_type") == db_type_is.POSTGRES.value: + self.assertEqual(frappe.conf.get("db_schema"), "pg_schema") + else: + # for mariadb this env should not have any effect + self.assertIsNone(frappe.conf.get("db_schema")) # now with configured settings without any influences from env - del os.environ["DB_PASSWORD"] - # finally connect should work without any error (when no wrong credentials are given via ENV) - frappe.connect() + frappe.init(current_site, force=True) frappe.db.connect() From 1b56b4f3f739aa1cc6d0e59b5c506ff4d780063d Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Fri, 5 Jul 2024 15:44:04 +0200 Subject: [PATCH 034/176] fix: Reset to orig env vars in specs --- frappe/__init__.py | 5 +++-- frappe/tests/test_db.py | 31 ++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index e911d538e7..e77de8afc3 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -448,8 +448,9 @@ def get_site_config(sites_path: str | None = None, site_path: str | None = None) # read password config["db_password"] = os.environ.get("FRAPPE_DB_PASSWORD") or config.get("db_password") - if config["db_type"] == "postgres": - config["db_schema"] = os.environ.get("FRAPPE_DB_PG_SCHEMA") or config.get("db_schema") + # TODO: possible after pg schema isluation fixes (PR 27000) + # if config["db_type"] == "postgres": + # config["db_schema"] = os.environ.get("FRAPPE_DB_PG_SCHEMA") or config.get("db_schema") # Allow externally extending the config with hooks if extra_config := config.get("extra_config"): diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 6ba0bb5ce2..d6c689239c 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1088,11 +1088,18 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): @contextlib.contextmanager def set_env_variable(key, value): + if orig_value_set := key in os.environ: + orig_value = os.environ.get(key) + os.environ[key] = value + try: yield finally: - del os.environ[key] + if orig_value_set: + os.environ[key] = orig_value + else: + del os.environ[key] current_site = frappe.local.site @@ -1144,20 +1151,22 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): with self.assertRaises(Exception) as cm: frappe.db.connect() - self.assertTrue("port 1111" in str(cm.exception)) + self.assertTrue("port 1111 failed" in str(cm.exception)) - # with wrong postgres schema - with set_env_variable("FRAPPE_DB_PG_SCHEMA", "pg_schema"): - frappe.init(current_site, force=True) - frappe.connect() + # TODO: possible after pg schema isluation fixes (PR 27000) + # # with wrong postgres schema + # with set_env_variable("FRAPPE_DB_PG_SCHEMA", "pg_schema"): + # frappe.init(current_site, force=True) + # frappe.connect() - if frappe.conf.get("db_type") == db_type_is.POSTGRES.value: - self.assertEqual(frappe.conf.get("db_schema"), "pg_schema") - else: - # for mariadb this env should not have any effect - self.assertIsNone(frappe.conf.get("db_schema")) + # if frappe.conf.get("db_type") == db_type_is.POSTGRES.value: + # self.assertEqual(frappe.conf.get("db_schema"), "pg_schema") + # else: + # # for mariadb this env should not have any effect + # self.assertIsNone(frappe.conf.get("db_schema")) # now with configured settings without any influences from env # finally connect should work without any error (when no wrong credentials are given via ENV) frappe.init(current_site, force=True) + frappe.connect() frappe.db.connect() From ea3d1365fef193d12e131df1589916a16492c005 Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Fri, 5 Jul 2024 16:26:51 +0200 Subject: [PATCH 035/176] fix: Adjusted the retrieved dbms errors to also handle mariadb errors correctly in specs. --- frappe/tests/test_db.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index d6c689239c..ff58b85ddc 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1085,6 +1085,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): def test_connect_fails_with_wrong_credentials_by_env(self) -> None: import contextlib import os + import re @contextlib.contextmanager def set_env_variable(key, value): @@ -1111,7 +1112,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): with self.assertRaises(Exception) as cm: frappe.db.connect() - self.assertTrue('database "dbiq"' in str(cm.exception)) + self.assertTrue(re.search(r"database [\"']dbiq[\"']", str(cm.exception))) # with wrong host with set_env_variable("FRAPPE_DB_HOST", "iqx.local"): @@ -1121,7 +1122,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): with self.assertRaises(Exception) as cm: frappe.db.connect() - self.assertTrue('host name "iqx.local"' in str(cm.exception)) + self.assertTrue(re.search(r"(host name|server on) [\"']iqx.local[\"']", str(cm.exception))) # with wrong user name with set_env_variable("FRAPPE_DB_USER", "uname"): @@ -1131,7 +1132,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): with self.assertRaises(Exception) as cm: frappe.db.connect() - self.assertTrue('user "uname"' in str(cm.exception)) + self.assertTrue(re.search(r"user [\"']uname[\"']", str(cm.exception))) # with wrong password with set_env_variable("FRAPPE_DB_PASSWORD", "pass"): @@ -1141,7 +1142,9 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): with self.assertRaises(Exception) as cm: frappe.db.connect() - self.assertTrue("password authentication failed" in str(cm.exception)) + self.assertTrue( + re.search(r"(password authentication failed|Access denied for)", str(cm.exception)) + ) # with wrong password with set_env_variable("FRAPPE_DB_PORT", "1111"): @@ -1151,7 +1154,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): with self.assertRaises(Exception) as cm: frappe.db.connect() - self.assertTrue("port 1111 failed" in str(cm.exception)) + self.assertTrue(re.search("(port 1111 failed|Errno 111)", str(cm.exception))) # TODO: possible after pg schema isluation fixes (PR 27000) # # with wrong postgres schema From c19e84451603128aaa5aff162e11a696ad3f8967 Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Fri, 5 Jul 2024 16:43:15 +0200 Subject: [PATCH 036/176] fix: Re-establish orig connection in tearDown for failing cases, that following specs dont rely on broken connection --- frappe/tests/test_db.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index ff58b85ddc..5d94adfd56 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1082,6 +1082,12 @@ class TestSqlIterator(FrappeTestCase): class TestDbConnectWithEnvCredentials(FrappeTestCase): + current_site = frappe.local.site + + def tearDown(self): + frappe.init(self.current_site, force=True) + frappe.connect() + def test_connect_fails_with_wrong_credentials_by_env(self) -> None: import contextlib import os @@ -1102,11 +1108,9 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): else: del os.environ[key] - current_site = frappe.local.site - # with wrong db name with set_env_variable("FRAPPE_DB_NAME", "dbiq"): - frappe.init(current_site, force=True) + frappe.init(self.current_site, force=True) frappe.connect() with self.assertRaises(Exception) as cm: @@ -1116,7 +1120,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): # with wrong host with set_env_variable("FRAPPE_DB_HOST", "iqx.local"): - frappe.init(current_site, force=True) + frappe.init(self.current_site, force=True) frappe.connect() with self.assertRaises(Exception) as cm: @@ -1126,7 +1130,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): # with wrong user name with set_env_variable("FRAPPE_DB_USER", "uname"): - frappe.init(current_site, force=True) + frappe.init(self.current_site, force=True) frappe.connect() with self.assertRaises(Exception) as cm: @@ -1136,7 +1140,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): # with wrong password with set_env_variable("FRAPPE_DB_PASSWORD", "pass"): - frappe.init(current_site, force=True) + frappe.init(self.current_site, force=True) frappe.connect() with self.assertRaises(Exception) as cm: @@ -1148,7 +1152,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): # with wrong password with set_env_variable("FRAPPE_DB_PORT", "1111"): - frappe.init(current_site, force=True) + frappe.init(self.current_site, force=True) frappe.connect() with self.assertRaises(Exception) as cm: @@ -1159,7 +1163,7 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): # TODO: possible after pg schema isluation fixes (PR 27000) # # with wrong postgres schema # with set_env_variable("FRAPPE_DB_PG_SCHEMA", "pg_schema"): - # frappe.init(current_site, force=True) + # frappe.init(self.current_site, force=True) # frappe.connect() # if frappe.conf.get("db_type") == db_type_is.POSTGRES.value: @@ -1170,6 +1174,6 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): # now with configured settings without any influences from env # finally connect should work without any error (when no wrong credentials are given via ENV) - frappe.init(current_site, force=True) + frappe.init(self.current_site, force=True) frappe.connect() frappe.db.connect() From 30736ef0e8415fd3b2846adfe1a5019092374b5e Mon Sep 17 00:00:00 2001 From: frappe-pr-bot Date: Sun, 7 Jul 2024 09:33:58 +0000 Subject: [PATCH 037/176] chore: update POT file --- frappe/locale/main.pot | 210 ++++++++++++++++++++++++++--------------- 1 file changed, 134 insertions(+), 76 deletions(-) diff --git a/frappe/locale/main.pot b/frappe/locale/main.pot index fce323b8bf..4606279c89 100644 --- a/frappe/locale/main.pot +++ b/frappe/locale/main.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Frappe Framework VERSION\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-06-30 09:33+0000\n" -"PO-Revision-Date: 2024-06-30 09:33+0000\n" +"POT-Creation-Date: 2024-07-07 09:33+0000\n" +"PO-Revision-Date: 2024-07-07 09:33+0000\n" "Last-Translator: developers@frappe.io\n" "Language-Team: developers@frappe.io\n" "MIME-Version: 1.0\n" @@ -1036,8 +1036,8 @@ msgid "Add Child" msgstr "" #: public/js/frappe/views/kanban/kanban_board.html:4 -#: public/js/frappe/views/reports/query_report.js:1696 -#: public/js/frappe/views/reports/query_report.js:1699 +#: public/js/frappe/views/reports/query_report.js:1681 +#: public/js/frappe/views/reports/query_report.js:1684 #: public/js/frappe/views/reports/report_view.js:324 #: public/js/frappe/views/reports/report_view.js:349 msgid "Add Column" @@ -3753,6 +3753,7 @@ msgstr "" #. Name of a DocType #: desk/doctype/calendar_view/calendar_view.json +#: public/js/frappe/list/base_list.js:208 msgid "Calendar View" msgstr "" @@ -3929,7 +3930,7 @@ msgstr "" msgid "Cannot Remove" msgstr "" -#: model/base_document.py:1072 +#: model/base_document.py:1073 msgid "Cannot Update After Submit" msgstr "" @@ -4017,7 +4018,7 @@ msgstr "" msgid "Cannot delete {0}" msgstr "" -#: utils/nestedset.py:296 +#: utils/nestedset.py:299 msgid "Cannot delete {0} as it has child nodes" msgstr "" @@ -4025,7 +4026,7 @@ msgstr "" msgid "Cannot edit Standard Dashboards" msgstr "" -#: email/doctype/notification/notification.py:121 +#: email/doctype/notification/notification.py:122 msgid "Cannot edit Standard Notification. To edit, please disable this and duplicate it" msgstr "" @@ -4094,7 +4095,7 @@ msgstr "" msgid "Cannot set 'Report' permission if 'Only If Creator' permission is set" msgstr "" -#: email/doctype/notification/notification.py:137 +#: email/doctype/notification/notification.py:138 msgid "Cannot set Notification on Document Type {0}" msgstr "" @@ -4270,6 +4271,8 @@ msgstr "" #. Label of the chart_name (Link) field in DocType 'Workspace Chart' #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/workspace_chart/workspace_chart.json +#: public/js/frappe/views/reports/query_report.js:289 +#: public/js/frappe/widgets/widget_dialog.js:137 msgid "Chart Name" msgstr "" @@ -4686,7 +4689,7 @@ msgctxt "Shrink code field." msgid "Collapse" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1979 +#: public/js/frappe/views/reports/query_report.js:1964 #: public/js/frappe/views/treeview.js:121 msgid "Collapse All" msgstr "" @@ -6218,6 +6221,10 @@ msgstr "" msgid "Dashboard Settings" msgstr "" +#: public/js/frappe/list/base_list.js:205 +msgid "Dashboard View" +msgstr "" + #. Label of the tab_break_2 (Tab Break) field in DocType 'Workspace' #: desk/doctype/workspace/workspace.json msgid "Dashboards" @@ -6799,7 +6806,8 @@ msgid "Department" msgstr "" #. Label of the dependencies (Data) field in DocType 'Workspace Link' -#: desk/doctype/workspace_link/workspace_link.json www/attribution.html:29 +#: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:318 www/attribution.html:29 msgid "Dependencies" msgstr "" @@ -7259,6 +7267,7 @@ msgstr "" #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: integrations/doctype/webhook/webhook.json #: printing/doctype/print_format/print_format.json +#: public/js/frappe/widgets/widget_dialog.js:164 #: website/doctype/website_slideshow/website_slideshow.js:18 msgid "DocType" msgstr "" @@ -7317,6 +7326,7 @@ msgstr "" #. Label of the doc_view (Select) field in DocType 'Workspace Shortcut' #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:477 msgid "DocType View" msgstr "" @@ -7840,7 +7850,7 @@ msgstr "" msgid "Download Your Data" msgstr "" -#: contacts/doctype/contact/contact.js:93 +#: contacts/doctype/contact/contact.js:98 msgid "Download vCard" msgstr "" @@ -8028,7 +8038,7 @@ msgstr "" #: public/js/frappe/form/templates/contact_list.html:7 #: public/js/frappe/form/toolbar.js:681 #: public/js/frappe/views/reports/query_report.js:815 -#: public/js/frappe/views/reports/query_report.js:1649 +#: public/js/frappe/views/reports/query_report.js:1634 #: public/js/frappe/views/workspace/workspace.js:460 #: public/js/frappe/views/workspace/workspace.js:816 #: public/js/frappe/widgets/base_widget.js:64 @@ -9006,9 +9016,9 @@ msgstr "" msgid "Error in Header/Footer Script" msgstr "" -#: email/doctype/notification/notification.py:394 -#: email/doctype/notification/notification.py:510 -#: email/doctype/notification/notification.py:516 +#: email/doctype/notification/notification.py:395 +#: email/doctype/notification/notification.py:511 +#: email/doctype/notification/notification.py:517 msgid "Error in Notification" msgstr "" @@ -9020,7 +9030,7 @@ msgstr "" msgid "Error while connecting to email account {0}" msgstr "" -#: email/doctype/notification/notification.py:507 +#: email/doctype/notification/notification.py:508 msgid "Error while evaluating Notification {0}. Please fix your template." msgstr "" @@ -9179,7 +9189,7 @@ msgstr "" msgid "Executing..." msgstr "" -#: public/js/frappe/views/reports/query_report.js:1993 +#: public/js/frappe/views/reports/query_report.js:1978 msgid "Execution Time: {0} sec" msgstr "" @@ -9197,7 +9207,7 @@ msgctxt "Enlarge code field." msgid "Expand" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1979 +#: public/js/frappe/views/reports/query_report.js:1964 #: public/js/frappe/views/treeview.js:125 msgid "Expand All" msgstr "" @@ -9253,7 +9263,7 @@ msgstr "" #: core/doctype/docperm/docperm.json core/doctype/recorder/recorder_list.js:37 #: public/js/frappe/data_import/data_exporter.js:91 #: public/js/frappe/data_import/data_exporter.js:242 -#: public/js/frappe/views/reports/query_report.js:1684 +#: public/js/frappe/views/reports/query_report.js:1669 #: public/js/frappe/views/reports/report_view.js:1550 msgid "Export" msgstr "" @@ -9594,7 +9604,7 @@ msgstr "" #: public/js/frappe/list/bulk_operations.js:297 #: public/js/frappe/list/list_view_permission_restrictions.html:3 #: public/js/frappe/views/reports/query_report.js:236 -#: public/js/frappe/views/reports/query_report.js:1738 +#: public/js/frappe/views/reports/query_report.js:1723 #: website/doctype/web_form_field/web_form_field.json #: website/doctype/web_form_list_column/web_form_list_column.json msgid "Field" @@ -9902,7 +9912,7 @@ msgstr "" #: desk/doctype/number_card/number_card.js:205 #: desk/doctype/number_card/number_card.js:336 #: email/doctype/auto_email_report/auto_email_report.js:90 -#: public/js/frappe/list/base_list.js:882 +#: public/js/frappe/list/base_list.js:890 #: public/js/frappe/ui/filters/filter_list.js:134 #: website/doctype/web_form/web_form.js:197 msgid "Filter" @@ -10339,7 +10349,7 @@ msgstr "" msgid "For Value" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1990 +#: public/js/frappe/views/reports/query_report.js:1975 #: public/js/frappe/views/reports/report_view.js:96 msgid "For comparison, use >5, <10 or =324. For ranges, use 5:10 (for values between 5 & 10)." msgstr "" @@ -10586,7 +10596,7 @@ msgstr "" msgid "From Date Field" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1704 +#: public/js/frappe/views/reports/query_report.js:1689 msgid "From Document Type" msgstr "" @@ -10682,6 +10692,10 @@ msgstr "" msgid "Gantt" msgstr "" +#: public/js/frappe/list/base_list.js:206 +msgid "Gantt View" +msgstr "" + #. Label of the gender (Link) field in DocType 'Contact' #. Name of a DocType #. Label of the gender (Data) field in DocType 'Gender' @@ -12053,6 +12067,10 @@ msgstr "" msgid "Image Link" msgstr "" +#: public/js/frappe/list/base_list.js:209 +msgid "Image View" +msgstr "" + #. Label of the image_width (Float) field in DocType 'Letter Head' #. Label of the footer_image_width (Float) field in DocType 'Letter Head' #: printing/doctype/letter_head/letter_head.json @@ -12324,6 +12342,10 @@ msgstr "" msgid "Inbox User" msgstr "" +#: public/js/frappe/list/base_list.js:210 +msgid "Inbox View" +msgstr "" + #. Label of the include_name_field (Check) field in DocType 'Form Tour' #: desk/doctype/form_tour/form_tour.json msgid "Include Name Field" @@ -12343,11 +12365,11 @@ msgstr "" msgid "Include Web View Link in Email" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1521 +#: public/js/frappe/views/reports/query_report.js:1506 msgid "Include filters" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1513 +#: public/js/frappe/views/reports/query_report.js:1498 msgid "Include indentation" msgstr "" @@ -12503,7 +12525,7 @@ msgstr "" #. Label of the insert_after (Select) field in DocType 'Custom Field' #: custom/doctype/custom_field/custom_field.json -#: public/js/frappe/views/reports/query_report.js:1744 +#: public/js/frappe/views/reports/query_report.js:1729 msgid "Insert After" msgstr "" @@ -12710,7 +12732,7 @@ msgstr "" msgid "Invalid \"mandatory_depends_on\" expression" msgstr "" -#: utils/nestedset.py:177 +#: utils/nestedset.py:178 msgid "Invalid Action" msgstr "" @@ -13081,6 +13103,7 @@ msgstr "" #. Label of the is_query_report (Check) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:336 msgid "Is Query Report" msgstr "" @@ -13184,7 +13207,7 @@ msgstr "" msgid "Item Type" msgstr "" -#: utils/nestedset.py:228 +#: utils/nestedset.py:229 msgid "Item cannot be added to its own descendants" msgstr "" @@ -13309,6 +13332,7 @@ msgstr "" #. Label of the kanban_board (Link) field in DocType 'Workspace Shortcut' #: desk/doctype/kanban_board/kanban_board.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:509 msgid "Kanban Board" msgstr "" @@ -13328,6 +13352,10 @@ msgctxt "Button in kanban view menu" msgid "Kanban Settings" msgstr "" +#: public/js/frappe/list/base_list.js:207 +msgid "Kanban View" +msgstr "" + #. Description of a DocType #: core/doctype/activity_log/activity_log.json msgid "Keep track of all update feeds" @@ -13573,7 +13601,10 @@ msgstr "" #: desk/doctype/workspace_quick_list/workspace_quick_list.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: printing/page/print_format_builder/print_format_builder.js:474 +#: public/js/frappe/widgets/widget_dialog.js:187 #: public/js/frappe/widgets/widget_dialog.js:255 +#: public/js/frappe/widgets/widget_dialog.js:304 +#: public/js/frappe/widgets/widget_dialog.js:421 #: public/js/frappe/widgets/widget_dialog.js:645 #: public/js/frappe/widgets/widget_dialog.js:678 #: templates/form_grid/fields.html:37 @@ -14140,6 +14171,8 @@ msgstr "" #. Label of the link_to (Dynamic Link) field in DocType 'Workspace Shortcut' #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:285 +#: public/js/frappe/widgets/widget_dialog.js:430 msgid "Link To" msgstr "" @@ -14149,6 +14182,7 @@ msgstr "" #. Label of the link_type (Select) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:277 msgid "Link Type" msgstr "" @@ -14192,7 +14226,7 @@ msgstr "" #. Label of the links (Table) field in DocType 'Customize Form' #. Label of the links (Table) field in DocType 'Workspace' #: contacts/doctype/address/address.js:39 contacts/doctype/address/address.json -#: contacts/doctype/contact/contact.js:87 contacts/doctype/contact/contact.json +#: contacts/doctype/contact/contact.js:92 contacts/doctype/contact/contact.json #: core/doctype/doctype/doctype.json #: custom/doctype/customize_form/customize_form.json #: desk/doctype/workspace/workspace.json public/js/frappe/form/toolbar.js:377 @@ -14245,6 +14279,10 @@ msgctxt "Button in list view menu" msgid "List Settings" msgstr "" +#: public/js/frappe/list/base_list.js:203 +msgid "List View" +msgstr "" + #. Name of a DocType #: desk/doctype/list_view_settings/list_view_settings.json msgid "List View Settings" @@ -14281,7 +14319,7 @@ msgstr "" msgid "Load Balancing" msgstr "" -#: public/js/frappe/list/base_list.js:378 +#: public/js/frappe/list/base_list.js:386 #: website/doctype/blog_post/templates/blog_post_list.html:50 #: website/doctype/help_article/templates/help_article_list.html:30 msgid "Load More" @@ -14295,7 +14333,7 @@ msgstr "" #: core/page/permission_manager/permission_manager.js:165 #: public/js/frappe/form/controls/multicheck.js:13 #: public/js/frappe/form/linked_with.js:13 -#: public/js/frappe/list/base_list.js:490 +#: public/js/frappe/list/base_list.js:498 #: public/js/frappe/list/list_view.js:335 public/js/frappe/ui/listing.html:16 #: public/js/frappe/views/reports/query_report.js:1017 msgid "Loading" @@ -14323,7 +14361,7 @@ msgstr "" #: public/js/frappe/views/kanban/kanban_board.html:11 #: public/js/frappe/widgets/chart_widget.js:50 #: public/js/frappe/widgets/number_card_widget.js:174 -#: public/js/frappe/widgets/quick_list_widget.js:126 +#: public/js/frappe/widgets/quick_list_widget.js:128 msgid "Loading..." msgstr "" @@ -14708,6 +14746,10 @@ msgstr "" msgid "Map Columns" msgstr "" +#: public/js/frappe/list/base_list.js:212 +msgid "Map View" +msgstr "" + #: public/js/frappe/data_import/import_preview.js:290 msgid "Map columns from {0} to fields in {1}" msgstr "" @@ -14938,7 +14980,7 @@ msgstr "" msgid "Merge with existing" msgstr "" -#: utils/nestedset.py:304 +#: utils/nestedset.py:307 msgid "Merging is only possible between Group-to-Group or Leaf Node-to-Leaf Node" msgstr "" @@ -15094,6 +15136,10 @@ msgstr "" msgid "Method" msgstr "" +#: __init__.py:936 +msgid "Method Not Allowed" +msgstr "" + #: desk/doctype/number_card/number_card.py:70 msgid "Method is required to create a number card" msgstr "" @@ -15485,7 +15531,7 @@ msgstr "" msgid "Mozilla doesn't support :has() so you can pass parent selector here as workaround" msgstr "" -#: utils/nestedset.py:328 +#: utils/nestedset.py:331 msgid "Multiple root nodes not allowed." msgstr "" @@ -15721,7 +15767,7 @@ msgstr "" msgid "Negative Value" msgstr "" -#: utils/nestedset.py:93 +#: utils/nestedset.py:94 msgid "Nested set error. Please contact the Administrator." msgstr "" @@ -16068,7 +16114,7 @@ msgstr "" #: public/js/form_builder/utils.js:341 #: public/js/frappe/form/controls/link.js:475 #: public/js/frappe/list/list_sidebar_group_by.js:223 -#: public/js/frappe/views/reports/query_report.js:1541 +#: public/js/frappe/views/reports/query_report.js:1526 #: website/doctype/help_article/templates/help_article.html:26 msgid "No" msgstr "" @@ -16112,7 +16158,7 @@ msgstr "" msgid "No Data to Show" msgstr "" -#: public/js/frappe/widgets/quick_list_widget.js:131 +#: public/js/frappe/widgets/quick_list_widget.js:133 msgid "No Data..." msgstr "" @@ -16579,7 +16625,7 @@ msgstr "" msgid "Not allowed for {0}: {1}" msgstr "" -#: email/doctype/notification/notification.py:391 +#: email/doctype/notification/notification.py:392 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "" @@ -16698,7 +16744,7 @@ msgstr "" msgid "Nothing left to undo" msgstr "" -#: public/js/frappe/list/base_list.js:362 +#: public/js/frappe/list/base_list.js:370 #: public/js/frappe/views/reports/query_report.js:105 #: templates/includes/list/list.html:7 #: website/doctype/blog_post/templates/blog_post_list.html:41 @@ -17104,9 +17150,14 @@ msgstr "" #. Label of the onboard (Check) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:330 msgid "Onboard" msgstr "" +#: public/js/frappe/widgets/widget_dialog.js:236 +msgid "Onboarding Name" +msgstr "" + #. Name of a DocType #: desk/doctype/onboarding_permission/onboarding_permission.json msgid "Onboarding Permission" @@ -17214,6 +17265,7 @@ msgstr "" #. Label of the only_for (Link) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:323 msgid "Only for" msgstr "" @@ -17563,7 +17615,7 @@ msgstr "" #: printing/page/print/print.js:71 #: public/js/frappe/form/templates/print_layout.html:44 -#: public/js/frappe/views/reports/query_report.js:1669 +#: public/js/frappe/views/reports/query_report.js:1654 msgid "PDF" msgstr "" @@ -17955,7 +18007,7 @@ msgid "Password not found for {0} {1} {2}" msgstr "" #: core/doctype/user/user.py:1021 -msgid "Password reset instructions have been sent to your email" +msgid "Password reset instructions have been sent to {}'s email" msgstr "" #: www/update-password.html:164 @@ -18355,7 +18407,7 @@ msgstr "" msgid "Please check the filter values set for Dashboard Chart: {}" msgstr "" -#: model/base_document.py:872 +#: model/base_document.py:873 msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "" @@ -18657,11 +18709,11 @@ msgstr "" msgid "Please specify a valid parent DocType for {0}" msgstr "" -#: email/doctype/notification/notification.py:87 +#: email/doctype/notification/notification.py:88 msgid "Please specify which date field must be checked" msgstr "" -#: email/doctype/notification/notification.py:90 +#: email/doctype/notification/notification.py:91 msgid "Please specify which value field must be checked" msgstr "" @@ -18994,7 +19046,7 @@ msgstr "" #: public/js/frappe/form/templates/print_layout.html:46 #: public/js/frappe/form/toolbar.js:332 public/js/frappe/form/toolbar.js:344 #: public/js/frappe/list/bulk_operations.js:87 -#: public/js/frappe/views/reports/query_report.js:1655 +#: public/js/frappe/views/reports/query_report.js:1640 #: public/js/frappe/views/reports/report_view.js:1460 #: public/js/frappe/views/treeview.js:469 www/printview.html:18 msgid "Print" @@ -19856,7 +19908,7 @@ msgstr "" msgid "Rebuild Tree" msgstr "" -#: utils/nestedset.py:176 +#: utils/nestedset.py:177 msgid "Rebuilding of tree is not supported for {}" msgstr "" @@ -20214,7 +20266,7 @@ msgstr "" #: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1196 #: public/js/frappe/form/templates/print_layout.html:6 #: public/js/frappe/list/base_list.js:66 -#: public/js/frappe/views/reports/query_report.js:1644 +#: public/js/frappe/views/reports/query_report.js:1629 #: public/js/frappe/views/treeview.js:475 #: public/js/frappe/widgets/chart_widget.js:290 #: public/js/frappe/widgets/number_card_widget.js:324 @@ -20312,7 +20364,7 @@ msgstr "" msgid "Reload File" msgstr "" -#: public/js/frappe/list/base_list.js:242 +#: public/js/frappe/list/base_list.js:250 msgid "Reload List" msgstr "" @@ -20581,7 +20633,7 @@ msgstr "" #: core/doctype/report/report.json #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/number_card/number_card.json -#: public/js/frappe/views/reports/query_report.js:1825 +#: public/js/frappe/views/reports/query_report.js:1810 msgid "Report Name" msgstr "" @@ -20604,6 +20656,10 @@ msgstr "" msgid "Report Type" msgstr "" +#: public/js/frappe/list/base_list.js:204 +msgid "Report View" +msgstr "" + #: core/doctype/doctype/doctype.py:1780 msgid "Report cannot be set for Single types" msgstr "" @@ -20638,7 +20694,7 @@ msgstr "" msgid "Report was not saved (there were errors)" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1863 +#: public/js/frappe/views/reports/query_report.js:1848 msgid "Report with more than 10 columns looks better in Landscape mode." msgstr "" @@ -21224,7 +21280,7 @@ msgstr "" msgid "Roles can be set for users from their User page." msgstr "" -#: utils/nestedset.py:277 +#: utils/nestedset.py:280 msgid "Root {0} cannot be deleted" msgstr "" @@ -21297,7 +21353,7 @@ msgstr "" msgid "Row # {0}: Non administrator user can not set the role {1} to the custom doctype" msgstr "" -#: model/base_document.py:903 +#: model/base_document.py:904 msgid "Row #{0}:" msgstr "" @@ -21581,11 +21637,11 @@ msgstr "" #: public/js/frappe/views/kanban/kanban_settings.js:45 #: public/js/frappe/views/kanban/kanban_settings.js:189 #: public/js/frappe/views/kanban/kanban_view.js:343 -#: public/js/frappe/views/reports/query_report.js:1817 +#: public/js/frappe/views/reports/query_report.js:1802 #: public/js/frappe/views/reports/report_view.js:1640 #: public/js/frappe/views/workspace/workspace.js:501 #: public/js/frappe/widgets/base_widget.js:142 -#: public/js/frappe/widgets/quick_list_widget.js:117 +#: public/js/frappe/widgets/quick_list_widget.js:119 #: public/js/print_format_builder/print_format_builder.bundle.js:15 #: public/js/workflow_builder/workflow_builder.bundle.js:33 msgid "Save" @@ -21612,7 +21668,7 @@ msgstr "" msgid "Save Filter" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1820 +#: public/js/frappe/views/reports/query_report.js:1805 msgid "Save Report" msgstr "" @@ -22736,7 +22792,7 @@ msgid "Set Filters" msgstr "" #: public/js/frappe/widgets/chart_widget.js:395 -#: public/js/frappe/widgets/quick_list_widget.js:102 +#: public/js/frappe/widgets/quick_list_widget.js:104 msgid "Set Filters for {0}" msgstr "" @@ -22952,7 +23008,7 @@ msgstr "" msgid "Setup Approval Workflows" msgstr "" -#: public/js/frappe/views/reports/query_report.js:1690 +#: public/js/frappe/views/reports/query_report.js:1675 #: public/js/frappe/views/reports/report_view.js:1618 msgid "Setup Auto Email" msgstr "" @@ -24991,7 +25047,7 @@ msgid "" "" msgstr "" -#: email/doctype/notification/notification.py:130 +#: email/doctype/notification/notification.py:131 msgid "The Condition '{0}' is invalid" msgstr "" @@ -25449,7 +25505,7 @@ msgstr "" msgid "This goes above the slideshow." msgstr "" -#: public/js/frappe/views/reports/query_report.js:2027 +#: public/js/frappe/views/reports/query_report.js:2012 msgid "This is a background report. Please set the appropriate filters and then generate a new one." msgstr "" @@ -26315,6 +26371,10 @@ msgstr "" msgid "Tree" msgstr "" +#: public/js/frappe/list/base_list.js:211 +msgid "Tree View" +msgstr "" + #. Description of the 'Is Tree' (Check) field in DocType 'DocType' #: core/doctype/doctype/doctype.json msgid "Tree structures are implemented using Nested Set" @@ -26420,6 +26480,7 @@ msgstr "" #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: public/js/frappe/views/file/file_view.js:337 +#: public/js/frappe/widgets/widget_dialog.js:399 #: social/doctype/energy_point_log/energy_point_log.json #: website/doctype/web_template/web_template.json www/attribution.html:35 msgid "Type" @@ -26502,6 +26563,7 @@ msgstr "" #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: integrations/doctype/integration_request/integration_request.json #: integrations/doctype/webhook_request_log/webhook_request_log.json +#: public/js/frappe/widgets/widget_dialog.js:469 #: website/doctype/top_bar_item/top_bar_item.json #: website/doctype/website_slideshow_item/website_slideshow_item.json msgid "URL" @@ -27178,7 +27240,7 @@ msgid "User Permission" msgstr "" #: core/page/permission_manager/permission_manager_help.html:30 -#: public/js/frappe/views/reports/query_report.js:1804 +#: public/js/frappe/views/reports/query_report.js:1789 #: public/js/frappe/views/reports/report_view.js:1666 msgid "User Permissions" msgstr "" @@ -27496,7 +27558,7 @@ msgstr "" msgid "Value To Be Set" msgstr "" -#: model/base_document.py:965 model/document.py:682 +#: model/base_document.py:966 model/document.py:682 msgid "Value cannot be changed for {0}" msgstr "" @@ -27539,7 +27601,7 @@ msgstr "" msgid "Value to Validate" msgstr "" -#: model/base_document.py:1035 +#: model/base_document.py:1036 msgid "Value too big" msgstr "" @@ -27638,7 +27700,7 @@ msgid "View Full Log" msgstr "" #: public/js/frappe/views/treeview.js:463 -#: public/js/frappe/widgets/quick_list_widget.js:245 +#: public/js/frappe/widgets/quick_list_widget.js:247 msgid "View List" msgstr "" @@ -28520,7 +28582,7 @@ msgstr "" msgid "Write" msgstr "" -#: model/base_document.py:875 +#: model/base_document.py:876 msgid "Wrong Fetch From value" msgstr "" @@ -28607,7 +28669,7 @@ msgstr "" #: public/js/form_builder/utils.js:336 #: public/js/frappe/form/controls/link.js:475 #: public/js/frappe/list/list_sidebar_group_by.js:223 -#: public/js/frappe/views/reports/query_report.js:1541 +#: public/js/frappe/views/reports/query_report.js:1526 #: website/doctype/help_article/templates/help_article.html:25 msgid "Yes" msgstr "" @@ -29820,7 +29882,7 @@ msgstr "" msgid "via Google Meet" msgstr "" -#: email/doctype/notification/notification.py:215 +#: email/doctype/notification/notification.py:216 msgid "via Notification" msgstr "" @@ -29963,7 +30025,7 @@ msgstr "" msgid "{0} Name" msgstr "" -#: model/base_document.py:1065 +#: model/base_document.py:1066 msgid "{0} Not allowed to change {1} after submission from {2} to {3}" msgstr "" @@ -29989,10 +30051,6 @@ msgstr "" msgid "{0} Tree" msgstr "" -#: public/js/frappe/list/base_list.js:209 -msgid "{0} View" -msgstr "" - #: public/js/frappe/form/footer/form_timeline.js:126 #: public/js/frappe/form/sidebar/form_sidebar.js:86 msgid "{0} Web page views" @@ -30607,11 +30665,11 @@ msgstr "" msgid "{0} {1} already exists" msgstr "" -#: model/base_document.py:908 +#: model/base_document.py:909 msgid "{0} {1} cannot be \"{2}\". It should be one of \"{3}\"" msgstr "" -#: utils/nestedset.py:337 +#: utils/nestedset.py:340 msgid "{0} {1} cannot be a leaf node as it has children" msgstr "" @@ -30631,11 +30689,11 @@ msgstr "" msgid "{0} {1}: Submitted Record cannot be deleted. You must {2} Cancel {3} it first." msgstr "" -#: model/base_document.py:1026 +#: model/base_document.py:1027 msgid "{0}, Row {1}" msgstr "" -#: model/base_document.py:1031 +#: model/base_document.py:1032 msgid "{0}: '{1}' ({3}) will get truncated, as max characters allowed is {2}" msgstr "" @@ -30728,7 +30786,7 @@ msgid "{0}: fieldname cannot be set to reserved keyword {1}" msgstr "" #: contacts/doctype/address/address.js:35 -#: contacts/doctype/contact/contact.js:83 +#: contacts/doctype/contact/contact.js:88 #: public/js/frappe/views/workspace/workspace.js:170 msgid "{0}: {1}" msgstr "" From c8ef58f7f40946c3e0511a061fbb492432a44384 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 8 Jul 2024 12:37:22 +0200 Subject: [PATCH 038/176] fix: input mode for numbers --- frappe/public/js/frappe/form/controls/data.js | 3 ++- frappe/public/js/frappe/form/controls/int.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/data.js b/frappe/public/js/frappe/form/controls/data.js index b090ed3cf2..a66aaa30b8 100644 --- a/frappe/public/js/frappe/form/controls/data.js +++ b/frappe/public/js/frappe/form/controls/data.js @@ -7,10 +7,11 @@ frappe.ui.form.ControlData = class ControlData extends frappe.ui.form.ControlInp make_input() { if (this.$input) return; - let { html_element, input_type } = this.constructor; + let { html_element, input_type, input_mode } = this.constructor; this.$input = $("<" + html_element + ">") .attr("type", input_type) + .attr("inputmode", input_mode) .attr("autocomplete", "off") .addClass("input-with-feedback form-control") .prependTo(this.input_area); diff --git a/frappe/public/js/frappe/form/controls/int.js b/frappe/public/js/frappe/form/controls/int.js index 122b43b498..48175a92c0 100644 --- a/frappe/public/js/frappe/form/controls/int.js +++ b/frappe/public/js/frappe/form/controls/int.js @@ -1,5 +1,6 @@ frappe.ui.form.ControlInt = class ControlInt extends frappe.ui.form.ControlData { static trigger_change_on_input_event = false; + static input_mode = "numeric"; make() { super.make(); } From 7df4185f875edeb3a2014ea40bca19f741977d68 Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Mon, 8 Jul 2024 15:16:51 +0200 Subject: [PATCH 039/176] fix: removed TODO marks --- frappe/__init__.py | 4 ---- frappe/tests/test_db.py | 12 ------------ 2 files changed, 16 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index e77de8afc3..4c1873ea9b 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -448,10 +448,6 @@ def get_site_config(sites_path: str | None = None, site_path: str | None = None) # read password config["db_password"] = os.environ.get("FRAPPE_DB_PASSWORD") or config.get("db_password") - # TODO: possible after pg schema isluation fixes (PR 27000) - # if config["db_type"] == "postgres": - # config["db_schema"] = os.environ.get("FRAPPE_DB_PG_SCHEMA") or config.get("db_schema") - # Allow externally extending the config with hooks if extra_config := config.get("extra_config"): if isinstance(extra_config, str): diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 5d94adfd56..ee57d48e94 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1160,18 +1160,6 @@ class TestDbConnectWithEnvCredentials(FrappeTestCase): self.assertTrue(re.search("(port 1111 failed|Errno 111)", str(cm.exception))) - # TODO: possible after pg schema isluation fixes (PR 27000) - # # with wrong postgres schema - # with set_env_variable("FRAPPE_DB_PG_SCHEMA", "pg_schema"): - # frappe.init(self.current_site, force=True) - # frappe.connect() - - # if frappe.conf.get("db_type") == db_type_is.POSTGRES.value: - # self.assertEqual(frappe.conf.get("db_schema"), "pg_schema") - # else: - # # for mariadb this env should not have any effect - # self.assertIsNone(frappe.conf.get("db_schema")) - # now with configured settings without any influences from env # finally connect should work without any error (when no wrong credentials are given via ENV) frappe.init(self.current_site, force=True) From 551d511789e808b99169b94f5f7a8ec1bc964e20 Mon Sep 17 00:00:00 2001 From: priyanshshah2442 Date: Tue, 9 Jul 2024 12:52:00 +0530 Subject: [PATCH 040/176] fix: unset cscript.is_onload flag after the form is rendered --- frappe/public/js/frappe/form/form.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 5410b1caec..b311030cf9 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -628,6 +628,7 @@ frappe.ui.form.Form = class FrappeForm { () => this.cscript.is_onload && this.is_new() && this.focus_on_first_input(), () => this.run_after_load_hook(), () => this.dashboard.after_refresh(), + () => (this.cscript.is_onload = false), ]); } else { this.refresh_header(switched); From d476cbdf84808638be12960f7de6aa82157f79a2 Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Tue, 9 Jul 2024 16:43:29 +0530 Subject: [PATCH 041/176] fix(Duration): save null for empty value --- frappe/public/js/frappe/form/controls/duration.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frappe/public/js/frappe/form/controls/duration.js b/frappe/public/js/frappe/form/controls/duration.js index 9ef8b3b1e2..bdce65d4a7 100644 --- a/frappe/public/js/frappe/form/controls/duration.js +++ b/frappe/public/js/frappe/form/controls/duration.js @@ -4,6 +4,13 @@ frappe.ui.form.ControlDuration = class ControlDuration extends frappe.ui.form.Co this.make_picker(); } + validate(value) { + if(!value) { + return null; + } + return super.validate(value); + } + make_picker() { this.inputs = []; this.set_duration_options(); From 342de10c506a25477e85859cdf150e2080431c0c Mon Sep 17 00:00:00 2001 From: priyanshshah2442 Date: Wed, 10 Jul 2024 10:45:33 +0530 Subject: [PATCH 042/176] fix: remove unsetting of in trigger_onload --- frappe/public/js/frappe/form/form.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index b311030cf9..7edf8544cc 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -550,7 +550,6 @@ frappe.ui.form.Form = class FrappeForm { } trigger_onload(switched) { - this.cscript.is_onload = false; if (!this.opendocs[this.docname]) { var me = this; this.cscript.is_onload = true; From 55db5dc37a4b62baeb5cbb310201dbc451990834 Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Wed, 10 Jul 2024 12:20:54 +0530 Subject: [PATCH 043/176] fix: linter check --- frappe/public/js/frappe/form/controls/duration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/duration.js b/frappe/public/js/frappe/form/controls/duration.js index bdce65d4a7..66f73060b2 100644 --- a/frappe/public/js/frappe/form/controls/duration.js +++ b/frappe/public/js/frappe/form/controls/duration.js @@ -5,7 +5,7 @@ frappe.ui.form.ControlDuration = class ControlDuration extends frappe.ui.form.Co } validate(value) { - if(!value) { + if (!value) { return null; } return super.validate(value); From c379815a4b205380252f9e667a6951e41f2ea8f3 Mon Sep 17 00:00:00 2001 From: Systonium Date: Thu, 4 Jul 2024 19:11:45 +0500 Subject: [PATCH 044/176] fix(System Health Report): Modified the fetch_scheduler function to use different SQL queries for different databases using frappe.db.multisql --- .../system_health_report.py | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/frappe/desk/doctype/system_health_report/system_health_report.py b/frappe/desk/doctype/system_health_report/system_health_report.py index 1f136d43b9..25a42e111c 100644 --- a/frappe/desk/doctype/system_health_report/system_health_report.py +++ b/frappe/desk/doctype/system_health_report/system_health_report.py @@ -186,19 +186,40 @@ class SystemHealthReport(Document): # Exclude "maybe" curently executing job upper_threshold = add_to_date(None, minutes=-30, as_datetime=True) self.scheduler_status = get_scheduler_status().get("status") - failing_jobs = frappe.db.sql( - """ - select scheduled_job_type, - avg(CASE WHEN status != 'Complete' THEN 1 ELSE 0 END) * 100 as failure_rate - from `tabScheduled Job Log` - where - creation > %(lower_threshold)s - and modified > %(lower_threshold)s - and creation < %(upper_threshold)s - group by scheduled_job_type - having failure_rate > 0 - order by failure_rate desc - limit 5""", + + mariadb_query = """ + SELECT scheduled_job_type, + AVG(CASE WHEN status != 'Complete' THEN 1 ELSE 0 END) * 100 AS failure_rate + FROM `tabScheduled Job Log` + WHERE + creation > %(lower_threshold)s + AND modified > %(lower_threshold)s + AND creation < %(upper_threshold)s + GROUP BY scheduled_job_type + HAVING failure_rate > 0 + ORDER BY failure_rate DESC + LIMIT 5 + """ + + postgres_query = """ + SELECT scheduled_job_type, + AVG(CASE WHEN status != 'Complete' THEN 1 ELSE 0 END) * 100 AS "failure_rate" + FROM "tabScheduled Job Log" + WHERE + creation > %(lower_threshold)s + AND modified > %(lower_threshold)s + AND creation < %(upper_threshold)s + GROUP BY scheduled_job_type + HAVING AVG(CASE WHEN status != 'Complete' THEN 1 ELSE 0 END) * 100 > 0 + ORDER BY "failure_rate" DESC + LIMIT 5 + """ + + failing_jobs = frappe.db.multisql( + { + "mariadb": mariadb_query, + "postgres": postgres_query, + }, {"lower_threshold": lower_threshold, "upper_threshold": upper_threshold}, as_dict=True, ) From 15daa011d590ebdbd5dc50b1ff8dc9dacb5845a7 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:27:04 +0200 Subject: [PATCH 045/176] fix: better label for list primary action (#27053) --- frappe/public/js/frappe/list/list_view.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 50b49f265c..7333a22281 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -260,12 +260,8 @@ 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); - - // Better style would be __("Add {0}", [doctype_name], "Primary action in list view") - // Keeping it like this to not disrupt existing translations - const label = `${__("Add", null, "Primary action in list view")} ${doctype_name}`; this.page.set_primary_action( - label, + __("Add {0}", [doctype_name], "Primary action in list view"), () => { if (this.settings.primary_action) { this.settings.primary_action(); From 34aedf7782fef0d93c0ef9e4997db42797df61f1 Mon Sep 17 00:00:00 2001 From: Kerem Kurtuldu Date: Thu, 11 Jul 2024 07:57:52 +0300 Subject: [PATCH 046/176] =?UTF-8?q?fix:=20update=20country=20name=20from?= =?UTF-8?q?=20T=C3=BCrkiye=20to=20T\u00fcrkiye=20and=20sort=20by=20name=20?= =?UTF-8?q?(#27069)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frappe/geo/country_info.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json index ff2c2d4ae6..163f7fd9c0 100644 --- a/frappe/geo/country_info.json +++ b/frappe/geo/country_info.json @@ -2731,18 +2731,6 @@ ], "isd": "+216" }, - "Türkiye": { - "code": "tr", - "currency": "TRY", - "currency_fraction": "Kuru\u015f", - "currency_fraction_units": 100, - "currency_symbol": "\u20ba", - "number_format": "#.###,##", - "timezones": [ - "Europe/Istanbul" - ], - "isd": "+90" - }, "Turkmenistan": { "code": "tm", "currency": "TMM", @@ -2774,6 +2762,18 @@ "Pacific/Funafuti" ], "isd": "+688" + }, + "T\u00fcrkiye": { + "code": "tr", + "currency": "TRY", + "currency_fraction": "Kuru\u015f", + "currency_fraction_units": 100, + "currency_symbol": "\u20ba", + "number_format": "#.###,##", + "timezones": [ + "Europe/Istanbul" + ], + "isd": "+90" }, "Uganda": { "code": "ug", From f72e632bcf29010e858e7897e42219c40df03229 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 11 Jul 2024 10:28:02 +0530 Subject: [PATCH 047/176] fix: sync translations from crowdin (#27031) --- frappe/locale/eo.po | 212 ++++++++++++++++++++++++++++---------------- frappe/locale/sv.po | 10 +-- 2 files changed, 140 insertions(+), 82 deletions(-) diff --git a/frappe/locale/eo.po b/frappe/locale/eo.po index 8305c8614a..7bd6eb076f 100644 --- a/frappe/locale/eo.po +++ b/frappe/locale/eo.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-06-30 09:33+0000\n" -"PO-Revision-Date: 2024-07-02 15:49\n" +"POT-Creation-Date: 2024-07-07 09:33+0000\n" +"PO-Revision-Date: 2024-07-10 16:24\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Esperanto\n" "MIME-Version: 1.0\n" @@ -1003,8 +1003,8 @@ msgid "Add Child" msgstr "crwdns90826:0crwdne90826:0" #: public/js/frappe/views/kanban/kanban_board.html:4 -#: public/js/frappe/views/reports/query_report.js:1696 -#: public/js/frappe/views/reports/query_report.js:1699 +#: public/js/frappe/views/reports/query_report.js:1681 +#: public/js/frappe/views/reports/query_report.js:1684 #: public/js/frappe/views/reports/report_view.js:324 #: public/js/frappe/views/reports/report_view.js:349 msgid "Add Column" @@ -3719,6 +3719,7 @@ msgstr "crwdns128570:0crwdne128570:0" #. Name of a DocType #: desk/doctype/calendar_view/calendar_view.json +#: public/js/frappe/list/base_list.js:208 msgid "Calendar View" msgstr "crwdns91974:0crwdne91974:0" @@ -3895,7 +3896,7 @@ msgstr "crwdns92056:0crwdne92056:0" msgid "Cannot Remove" msgstr "crwdns92058:0crwdne92058:0" -#: model/base_document.py:1072 +#: model/base_document.py:1073 msgid "Cannot Update After Submit" msgstr "crwdns92060:0crwdne92060:0" @@ -3983,7 +3984,7 @@ msgstr "crwdns92100:0{0}crwdne92100:0" msgid "Cannot delete {0}" msgstr "crwdns92102:0{0}crwdne92102:0" -#: utils/nestedset.py:296 +#: utils/nestedset.py:299 msgid "Cannot delete {0} as it has child nodes" msgstr "crwdns92104:0{0}crwdne92104:0" @@ -3991,7 +3992,7 @@ msgstr "crwdns92104:0{0}crwdne92104:0" msgid "Cannot edit Standard Dashboards" msgstr "crwdns92106:0crwdne92106:0" -#: email/doctype/notification/notification.py:121 +#: email/doctype/notification/notification.py:122 msgid "Cannot edit Standard Notification. To edit, please disable this and duplicate it" msgstr "crwdns92108:0crwdne92108:0" @@ -4060,7 +4061,7 @@ msgstr "crwdns92136:0crwdne92136:0" msgid "Cannot set 'Report' permission if 'Only If Creator' permission is set" msgstr "crwdns110830:0crwdne110830:0" -#: email/doctype/notification/notification.py:137 +#: email/doctype/notification/notification.py:138 msgid "Cannot set Notification on Document Type {0}" msgstr "crwdns92138:0{0}crwdne92138:0" @@ -4234,6 +4235,8 @@ msgstr "crwdns128610:0crwdne128610:0" #. Label of the chart_name (Link) field in DocType 'Workspace Chart' #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/workspace_chart/workspace_chart.json +#: public/js/frappe/views/reports/query_report.js:289 +#: public/js/frappe/widgets/widget_dialog.js:137 msgid "Chart Name" msgstr "crwdns128612:0crwdne128612:0" @@ -4650,7 +4653,7 @@ msgctxt "Shrink code field." msgid "Collapse" msgstr "crwdns92402:0crwdne92402:0" -#: public/js/frappe/views/reports/query_report.js:1979 +#: public/js/frappe/views/reports/query_report.js:1964 #: public/js/frappe/views/treeview.js:121 msgid "Collapse All" msgstr "crwdns92404:0crwdne92404:0" @@ -6179,6 +6182,10 @@ msgstr "crwdns128842:0crwdne128842:0" msgid "Dashboard Settings" msgstr "crwdns93118:0crwdne93118:0" +#: public/js/frappe/list/base_list.js:205 +msgid "Dashboard View" +msgstr "crwdns142844:0crwdne142844:0" + #. Label of the tab_break_2 (Tab Break) field in DocType 'Workspace' #: desk/doctype/workspace/workspace.json msgid "Dashboards" @@ -6760,7 +6767,8 @@ msgid "Department" msgstr "crwdns128922:0crwdne128922:0" #. Label of the dependencies (Data) field in DocType 'Workspace Link' -#: desk/doctype/workspace_link/workspace_link.json www/attribution.html:29 +#: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:318 www/attribution.html:29 msgid "Dependencies" msgstr "crwdns112688:0crwdne112688:0" @@ -7219,6 +7227,7 @@ msgstr "crwdns93582:0{0}crwdne93582:0" #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: integrations/doctype/webhook/webhook.json #: printing/doctype/print_format/print_format.json +#: public/js/frappe/widgets/widget_dialog.js:164 #: website/doctype/website_slideshow/website_slideshow.js:18 msgid "DocType" msgstr "crwdns93584:0crwdne93584:0" @@ -7277,6 +7286,7 @@ msgstr "crwdns93632:0crwdne93632:0" #. Label of the doc_view (Select) field in DocType 'Workspace Shortcut' #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:477 msgid "DocType View" msgstr "crwdns128992:0crwdne128992:0" @@ -7800,7 +7810,7 @@ msgstr "crwdns129042:0crwdne129042:0" msgid "Download Your Data" msgstr "crwdns93896:0crwdne93896:0" -#: contacts/doctype/contact/contact.js:93 +#: contacts/doctype/contact/contact.js:98 msgid "Download vCard" msgstr "crwdns140790:0crwdne140790:0" @@ -7988,7 +7998,7 @@ msgstr "crwdns93972:0crwdne93972:0" #: public/js/frappe/form/templates/contact_list.html:7 #: public/js/frappe/form/toolbar.js:681 #: public/js/frappe/views/reports/query_report.js:815 -#: public/js/frappe/views/reports/query_report.js:1649 +#: public/js/frappe/views/reports/query_report.js:1634 #: public/js/frappe/views/workspace/workspace.js:460 #: public/js/frappe/views/workspace/workspace.js:816 #: public/js/frappe/widgets/base_widget.js:64 @@ -8965,9 +8975,9 @@ msgstr "crwdns94422:0crwdne94422:0" msgid "Error in Header/Footer Script" msgstr "crwdns110924:0crwdne110924:0" -#: email/doctype/notification/notification.py:394 -#: email/doctype/notification/notification.py:510 -#: email/doctype/notification/notification.py:516 +#: email/doctype/notification/notification.py:395 +#: email/doctype/notification/notification.py:511 +#: email/doctype/notification/notification.py:517 msgid "Error in Notification" msgstr "crwdns94424:0crwdne94424:0" @@ -8979,7 +8989,7 @@ msgstr "crwdns94426:0{0}crwdnd94426:0{1}crwdne94426:0" msgid "Error while connecting to email account {0}" msgstr "crwdns94428:0{0}crwdne94428:0" -#: email/doctype/notification/notification.py:507 +#: email/doctype/notification/notification.py:508 msgid "Error while evaluating Notification {0}. Please fix your template." msgstr "crwdns94430:0{0}crwdne94430:0" @@ -9136,7 +9146,7 @@ msgstr "crwdns94494:0crwdne94494:0" msgid "Executing..." msgstr "crwdns94496:0crwdne94496:0" -#: public/js/frappe/views/reports/query_report.js:1993 +#: public/js/frappe/views/reports/query_report.js:1978 msgid "Execution Time: {0} sec" msgstr "crwdns94498:0{0}crwdne94498:0" @@ -9154,7 +9164,7 @@ msgctxt "Enlarge code field." msgid "Expand" msgstr "crwdns94504:0crwdne94504:0" -#: public/js/frappe/views/reports/query_report.js:1979 +#: public/js/frappe/views/reports/query_report.js:1964 #: public/js/frappe/views/treeview.js:125 msgid "Expand All" msgstr "crwdns94506:0crwdne94506:0" @@ -9210,7 +9220,7 @@ msgstr "crwdns129232:0crwdne129232:0" #: core/doctype/docperm/docperm.json core/doctype/recorder/recorder_list.js:37 #: public/js/frappe/data_import/data_exporter.js:91 #: public/js/frappe/data_import/data_exporter.js:242 -#: public/js/frappe/views/reports/query_report.js:1684 +#: public/js/frappe/views/reports/query_report.js:1669 #: public/js/frappe/views/reports/report_view.js:1550 msgid "Export" msgstr "crwdns94526:0crwdne94526:0" @@ -9551,7 +9561,7 @@ msgstr "crwdns94660:0crwdne94660:0" #: public/js/frappe/list/bulk_operations.js:297 #: public/js/frappe/list/list_view_permission_restrictions.html:3 #: public/js/frappe/views/reports/query_report.js:236 -#: public/js/frappe/views/reports/query_report.js:1738 +#: public/js/frappe/views/reports/query_report.js:1723 #: website/doctype/web_form_field/web_form_field.json #: website/doctype/web_form_list_column/web_form_list_column.json msgid "Field" @@ -9859,7 +9869,7 @@ msgstr "crwdns94824:0crwdne94824:0" #: desk/doctype/number_card/number_card.js:205 #: desk/doctype/number_card/number_card.js:336 #: email/doctype/auto_email_report/auto_email_report.js:90 -#: public/js/frappe/list/base_list.js:882 +#: public/js/frappe/list/base_list.js:890 #: public/js/frappe/ui/filters/filter_list.js:134 #: website/doctype/web_form/web_form.js:197 msgid "Filter" @@ -10295,7 +10305,7 @@ msgstr "crwdns95024:0crwdne95024:0" msgid "For Value" msgstr "crwdns129392:0crwdne129392:0" -#: public/js/frappe/views/reports/query_report.js:1990 +#: public/js/frappe/views/reports/query_report.js:1975 #: public/js/frappe/views/reports/report_view.js:96 msgid "For comparison, use >5, <10 or =324. For ranges, use 5:10 (for values between 5 & 10)." msgstr "crwdns95034:0crwdne95034:0" @@ -10542,7 +10552,7 @@ msgstr "crwdns95156:0crwdne95156:0" msgid "From Date Field" msgstr "crwdns129430:0crwdne129430:0" -#: public/js/frappe/views/reports/query_report.js:1704 +#: public/js/frappe/views/reports/query_report.js:1689 msgid "From Document Type" msgstr "crwdns95162:0crwdne95162:0" @@ -10638,6 +10648,10 @@ msgstr "crwdns129446:0crwdne129446:0" msgid "Gantt" msgstr "crwdns95208:0crwdne95208:0" +#: public/js/frappe/list/base_list.js:206 +msgid "Gantt View" +msgstr "crwdns142846:0crwdne142846:0" + #. Label of the gender (Link) field in DocType 'Contact' #. Name of a DocType #. Label of the gender (Data) field in DocType 'Gender' @@ -12009,6 +12023,10 @@ msgstr "crwdns129686:0crwdne129686:0" msgid "Image Link" msgstr "crwdns129688:0crwdne129688:0" +#: public/js/frappe/list/base_list.js:209 +msgid "Image View" +msgstr "crwdns142848:0crwdne142848:0" + #. Label of the image_width (Float) field in DocType 'Letter Head' #. Label of the footer_image_width (Float) field in DocType 'Letter Head' #: printing/doctype/letter_head/letter_head.json @@ -12280,6 +12298,10 @@ msgstr "crwdns95966:0crwdne95966:0" msgid "Inbox User" msgstr "crwdns95970:0crwdne95970:0" +#: public/js/frappe/list/base_list.js:210 +msgid "Inbox View" +msgstr "crwdns142850:0crwdne142850:0" + #. Label of the include_name_field (Check) field in DocType 'Form Tour' #: desk/doctype/form_tour/form_tour.json msgid "Include Name Field" @@ -12299,11 +12321,11 @@ msgstr "crwdns95976:0crwdne95976:0" msgid "Include Web View Link in Email" msgstr "crwdns129732:0crwdne129732:0" -#: public/js/frappe/views/reports/query_report.js:1521 +#: public/js/frappe/views/reports/query_report.js:1506 msgid "Include filters" msgstr "crwdns95980:0crwdne95980:0" -#: public/js/frappe/views/reports/query_report.js:1513 +#: public/js/frappe/views/reports/query_report.js:1498 msgid "Include indentation" msgstr "crwdns95982:0crwdne95982:0" @@ -12459,7 +12481,7 @@ msgstr "crwdns110970:0crwdne110970:0" #. Label of the insert_after (Select) field in DocType 'Custom Field' #: custom/doctype/custom_field/custom_field.json -#: public/js/frappe/views/reports/query_report.js:1744 +#: public/js/frappe/views/reports/query_report.js:1729 msgid "Insert After" msgstr "crwdns96046:0crwdne96046:0" @@ -12666,7 +12688,7 @@ msgstr "crwdns96132:0{0}crwdne96132:0" msgid "Invalid \"mandatory_depends_on\" expression" msgstr "crwdns96134:0crwdne96134:0" -#: utils/nestedset.py:177 +#: utils/nestedset.py:178 msgid "Invalid Action" msgstr "crwdns96136:0crwdne96136:0" @@ -13037,6 +13059,7 @@ msgstr "crwdns96308:0crwdne96308:0" #. Label of the is_query_report (Check) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:336 msgid "Is Query Report" msgstr "crwdns129828:0crwdne129828:0" @@ -13140,7 +13163,7 @@ msgstr "crwdns129850:0crwdne129850:0" msgid "Item Type" msgstr "crwdns129852:0crwdne129852:0" -#: utils/nestedset.py:228 +#: utils/nestedset.py:229 msgid "Item cannot be added to its own descendants" msgstr "crwdns96372:0crwdne96372:0" @@ -13265,6 +13288,7 @@ msgstr "crwdns129880:0crwdne129880:0" #. Label of the kanban_board (Link) field in DocType 'Workspace Shortcut' #: desk/doctype/kanban_board/kanban_board.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:509 msgid "Kanban Board" msgstr "crwdns96432:0crwdne96432:0" @@ -13284,6 +13308,10 @@ msgctxt "Button in kanban view menu" msgid "Kanban Settings" msgstr "crwdns96444:0crwdne96444:0" +#: public/js/frappe/list/base_list.js:207 +msgid "Kanban View" +msgstr "crwdns142852:0crwdne142852:0" + #. Description of a DocType #: core/doctype/activity_log/activity_log.json msgid "Keep track of all update feeds" @@ -13529,7 +13557,10 @@ msgstr "crwdns96524:0{0}crwdne96524:0" #: desk/doctype/workspace_quick_list/workspace_quick_list.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: printing/page/print_format_builder/print_format_builder.js:474 +#: public/js/frappe/widgets/widget_dialog.js:187 #: public/js/frappe/widgets/widget_dialog.js:255 +#: public/js/frappe/widgets/widget_dialog.js:304 +#: public/js/frappe/widgets/widget_dialog.js:421 #: public/js/frappe/widgets/widget_dialog.js:645 #: public/js/frappe/widgets/widget_dialog.js:678 #: templates/form_grid/fields.html:37 @@ -14096,6 +14127,8 @@ msgstr "crwdns130038:0crwdne130038:0" #. Label of the link_to (Dynamic Link) field in DocType 'Workspace Shortcut' #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:285 +#: public/js/frappe/widgets/widget_dialog.js:430 msgid "Link To" msgstr "crwdns130040:0crwdne130040:0" @@ -14105,6 +14138,7 @@ msgstr "crwdns110990:0crwdne110990:0" #. Label of the link_type (Select) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:277 msgid "Link Type" msgstr "crwdns130042:0crwdne130042:0" @@ -14148,7 +14182,7 @@ msgstr "crwdns96840:0crwdne96840:0" #. Label of the links (Table) field in DocType 'Customize Form' #. Label of the links (Table) field in DocType 'Workspace' #: contacts/doctype/address/address.js:39 contacts/doctype/address/address.json -#: contacts/doctype/contact/contact.js:87 contacts/doctype/contact/contact.json +#: contacts/doctype/contact/contact.js:92 contacts/doctype/contact/contact.json #: core/doctype/doctype/doctype.json #: custom/doctype/customize_form/customize_form.json #: desk/doctype/workspace/workspace.json public/js/frappe/form/toolbar.js:377 @@ -14201,6 +14235,10 @@ msgctxt "Button in list view menu" msgid "List Settings" msgstr "crwdns96868:0crwdne96868:0" +#: public/js/frappe/list/base_list.js:203 +msgid "List View" +msgstr "crwdns142854:0crwdne142854:0" + #. Name of a DocType #: desk/doctype/list_view_settings/list_view_settings.json msgid "List View Settings" @@ -14237,7 +14275,7 @@ msgstr "crwdns96884:0crwdne96884:0" msgid "Load Balancing" msgstr "crwdns130066:0crwdne130066:0" -#: public/js/frappe/list/base_list.js:378 +#: public/js/frappe/list/base_list.js:386 #: website/doctype/blog_post/templates/blog_post_list.html:50 #: website/doctype/help_article/templates/help_article_list.html:30 msgid "Load More" @@ -14251,7 +14289,7 @@ msgstr "crwdns96890:0crwdne96890:0" #: core/page/permission_manager/permission_manager.js:165 #: public/js/frappe/form/controls/multicheck.js:13 #: public/js/frappe/form/linked_with.js:13 -#: public/js/frappe/list/base_list.js:490 +#: public/js/frappe/list/base_list.js:498 #: public/js/frappe/list/list_view.js:335 public/js/frappe/ui/listing.html:16 #: public/js/frappe/views/reports/query_report.js:1017 msgid "Loading" @@ -14279,7 +14317,7 @@ msgstr "crwdns110996:0crwdne110996:0" #: public/js/frappe/views/kanban/kanban_board.html:11 #: public/js/frappe/widgets/chart_widget.js:50 #: public/js/frappe/widgets/number_card_widget.js:174 -#: public/js/frappe/widgets/quick_list_widget.js:126 +#: public/js/frappe/widgets/quick_list_widget.js:128 msgid "Loading..." msgstr "crwdns96898:0crwdne96898:0" @@ -14664,6 +14702,10 @@ msgstr "crwdns130124:0crwdne130124:0" msgid "Map Columns" msgstr "crwdns97072:0crwdne97072:0" +#: public/js/frappe/list/base_list.js:212 +msgid "Map View" +msgstr "crwdns142856:0crwdne142856:0" + #: public/js/frappe/data_import/import_preview.js:290 msgid "Map columns from {0} to fields in {1}" msgstr "crwdns111002:0{0}crwdnd111002:0{1}crwdne111002:0" @@ -14893,7 +14935,7 @@ msgstr "crwdns97168:0crwdne97168:0" msgid "Merge with existing" msgstr "crwdns97170:0crwdne97170:0" -#: utils/nestedset.py:304 +#: utils/nestedset.py:307 msgid "Merging is only possible between Group-to-Group or Leaf Node-to-Leaf Node" msgstr "crwdns97172:0crwdne97172:0" @@ -15049,6 +15091,10 @@ msgstr "crwdns97252:0crwdne97252:0" msgid "Method" msgstr "crwdns130200:0crwdne130200:0" +#: __init__.py:936 +msgid "Method Not Allowed" +msgstr "crwdns142858:0crwdne142858:0" + #: desk/doctype/number_card/number_card.py:70 msgid "Method is required to create a number card" msgstr "crwdns97266:0crwdne97266:0" @@ -15440,7 +15486,7 @@ msgstr "crwdns130234:0crwdne130234:0" msgid "Mozilla doesn't support :has() so you can pass parent selector here as workaround" msgstr "crwdns130236:0crwdne130236:0" -#: utils/nestedset.py:328 +#: utils/nestedset.py:331 msgid "Multiple root nodes not allowed." msgstr "crwdns97478:0crwdne97478:0" @@ -15674,7 +15720,7 @@ msgstr "crwdns97574:0crwdne97574:0" msgid "Negative Value" msgstr "crwdns97576:0crwdne97576:0" -#: utils/nestedset.py:93 +#: utils/nestedset.py:94 msgid "Nested set error. Please contact the Administrator." msgstr "crwdns97578:0crwdne97578:0" @@ -16021,7 +16067,7 @@ msgstr "crwdns130294:0crwdne130294:0" #: public/js/form_builder/utils.js:341 #: public/js/frappe/form/controls/link.js:475 #: public/js/frappe/list/list_sidebar_group_by.js:223 -#: public/js/frappe/views/reports/query_report.js:1541 +#: public/js/frappe/views/reports/query_report.js:1526 #: website/doctype/help_article/templates/help_article.html:26 msgid "No" msgstr "crwdns97696:0crwdne97696:0" @@ -16065,7 +16111,7 @@ msgstr "crwdns97718:0crwdne97718:0" msgid "No Data to Show" msgstr "crwdns111038:0crwdne111038:0" -#: public/js/frappe/widgets/quick_list_widget.js:131 +#: public/js/frappe/widgets/quick_list_widget.js:133 msgid "No Data..." msgstr "crwdns111040:0crwdne111040:0" @@ -16532,7 +16578,7 @@ msgstr "crwdns97892:0crwdne97892:0" msgid "Not allowed for {0}: {1}" msgstr "crwdns97894:0{0}crwdnd97894:0{1}crwdne97894:0" -#: email/doctype/notification/notification.py:391 +#: email/doctype/notification/notification.py:392 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "crwdns97896:0{0}crwdnd97896:0{0}crwdne97896:0" @@ -16651,7 +16697,7 @@ msgstr "crwdns97940:0crwdne97940:0" msgid "Nothing left to undo" msgstr "crwdns97942:0crwdne97942:0" -#: public/js/frappe/list/base_list.js:362 +#: public/js/frappe/list/base_list.js:370 #: public/js/frappe/views/reports/query_report.js:105 #: templates/includes/list/list.html:7 #: website/doctype/blog_post/templates/blog_post_list.html:41 @@ -17057,9 +17103,14 @@ msgstr "crwdns111096:0{0}crwdnd111096:0{1}crwdne111096:0" #. Label of the onboard (Check) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:330 msgid "Onboard" msgstr "crwdns130402:0crwdne130402:0" +#: public/js/frappe/widgets/widget_dialog.js:236 +msgid "Onboarding Name" +msgstr "crwdns142860:0crwdne142860:0" + #. Name of a DocType #: desk/doctype/onboarding_permission/onboarding_permission.json msgid "Onboarding Permission" @@ -17167,6 +17218,7 @@ msgstr "crwdns127690:0crwdne127690:0" #. Label of the only_for (Link) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:323 msgid "Only for" msgstr "crwdns130412:0crwdne130412:0" @@ -17516,7 +17568,7 @@ msgstr "crwdns130460:0crwdne130460:0" #: printing/page/print/print.js:71 #: public/js/frappe/form/templates/print_layout.html:44 -#: public/js/frappe/views/reports/query_report.js:1669 +#: public/js/frappe/views/reports/query_report.js:1654 msgid "PDF" msgstr "crwdns98288:0crwdne98288:0" @@ -17908,8 +17960,8 @@ msgid "Password not found for {0} {1} {2}" msgstr "crwdns98464:0{0}crwdnd98464:0{1}crwdnd98464:0{2}crwdne98464:0" #: core/doctype/user/user.py:1021 -msgid "Password reset instructions have been sent to your email" -msgstr "crwdns98466:0crwdne98466:0" +msgid "Password reset instructions have been sent to {}'s email" +msgstr "crwdns142862:0crwdne142862:0" #: www/update-password.html:164 msgid "Password set" @@ -18308,7 +18360,7 @@ msgstr "crwdns98646:0crwdne98646:0" msgid "Please check the filter values set for Dashboard Chart: {}" msgstr "crwdns98648:0crwdne98648:0" -#: model/base_document.py:872 +#: model/base_document.py:873 msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "crwdns98650:0{0}crwdne98650:0" @@ -18610,11 +18662,11 @@ msgstr "crwdns98790:0crwdne98790:0" msgid "Please specify a valid parent DocType for {0}" msgstr "crwdns98792:0{0}crwdne98792:0" -#: email/doctype/notification/notification.py:87 +#: email/doctype/notification/notification.py:88 msgid "Please specify which date field must be checked" msgstr "crwdns98794:0crwdne98794:0" -#: email/doctype/notification/notification.py:90 +#: email/doctype/notification/notification.py:91 msgid "Please specify which value field must be checked" msgstr "crwdns98796:0crwdne98796:0" @@ -18947,7 +18999,7 @@ msgstr "crwdns112704:0{0}crwdne112704:0" #: public/js/frappe/form/templates/print_layout.html:46 #: public/js/frappe/form/toolbar.js:332 public/js/frappe/form/toolbar.js:344 #: public/js/frappe/list/bulk_operations.js:87 -#: public/js/frappe/views/reports/query_report.js:1655 +#: public/js/frappe/views/reports/query_report.js:1640 #: public/js/frappe/views/reports/report_view.js:1460 #: public/js/frappe/views/treeview.js:469 www/printview.html:18 msgid "Print" @@ -19809,7 +19861,7 @@ msgstr "crwdns99328:0crwdne99328:0" msgid "Rebuild Tree" msgstr "crwdns99330:0crwdne99330:0" -#: utils/nestedset.py:176 +#: utils/nestedset.py:177 msgid "Rebuilding of tree is not supported for {}" msgstr "crwdns99332:0crwdne99332:0" @@ -20167,7 +20219,7 @@ msgstr "crwdns99526:0crwdne99526:0" #: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1196 #: public/js/frappe/form/templates/print_layout.html:6 #: public/js/frappe/list/base_list.js:66 -#: public/js/frappe/views/reports/query_report.js:1644 +#: public/js/frappe/views/reports/query_report.js:1629 #: public/js/frappe/views/treeview.js:475 #: public/js/frappe/widgets/chart_widget.js:290 #: public/js/frappe/widgets/number_card_widget.js:324 @@ -20265,7 +20317,7 @@ msgstr "crwdns99566:0crwdne99566:0" msgid "Reload File" msgstr "crwdns111162:0crwdne111162:0" -#: public/js/frappe/list/base_list.js:242 +#: public/js/frappe/list/base_list.js:250 msgid "Reload List" msgstr "crwdns99568:0crwdne99568:0" @@ -20534,7 +20586,7 @@ msgstr "crwdns99694:0crwdne99694:0" #: core/doctype/report/report.json #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/number_card/number_card.json -#: public/js/frappe/views/reports/query_report.js:1825 +#: public/js/frappe/views/reports/query_report.js:1810 msgid "Report Name" msgstr "crwdns99696:0crwdne99696:0" @@ -20557,6 +20609,10 @@ msgstr "crwdns130836:0crwdne130836:0" msgid "Report Type" msgstr "crwdns130838:0crwdne130838:0" +#: public/js/frappe/list/base_list.js:204 +msgid "Report View" +msgstr "crwdns142864:0crwdne142864:0" + #: core/doctype/doctype/doctype.py:1780 msgid "Report cannot be set for Single types" msgstr "crwdns99718:0crwdne99718:0" @@ -20591,7 +20647,7 @@ msgstr "crwdns99730:0crwdne99730:0" msgid "Report was not saved (there were errors)" msgstr "crwdns99732:0crwdne99732:0" -#: public/js/frappe/views/reports/query_report.js:1863 +#: public/js/frappe/views/reports/query_report.js:1848 msgid "Report with more than 10 columns looks better in Landscape mode." msgstr "crwdns99734:0crwdne99734:0" @@ -21177,7 +21233,7 @@ msgstr "crwdns130922:0crwdne130922:0" msgid "Roles can be set for users from their User page." msgstr "crwdns111176:0crwdne111176:0" -#: utils/nestedset.py:277 +#: utils/nestedset.py:280 msgid "Root {0} cannot be deleted" msgstr "crwdns100012:0{0}crwdne100012:0" @@ -21250,7 +21306,7 @@ msgstr "crwdns111178:0crwdne111178:0" msgid "Row # {0}: Non administrator user can not set the role {1} to the custom doctype" msgstr "crwdns100056:0{0}crwdnd100056:0{1}crwdne100056:0" -#: model/base_document.py:903 +#: model/base_document.py:904 msgid "Row #{0}:" msgstr "crwdns100058:0#{0}crwdne100058:0" @@ -21534,11 +21590,11 @@ msgstr "crwdns130978:0crwdne130978:0" #: public/js/frappe/views/kanban/kanban_settings.js:45 #: public/js/frappe/views/kanban/kanban_settings.js:189 #: public/js/frappe/views/kanban/kanban_view.js:343 -#: public/js/frappe/views/reports/query_report.js:1817 +#: public/js/frappe/views/reports/query_report.js:1802 #: public/js/frappe/views/reports/report_view.js:1640 #: public/js/frappe/views/workspace/workspace.js:501 #: public/js/frappe/widgets/base_widget.js:142 -#: public/js/frappe/widgets/quick_list_widget.js:117 +#: public/js/frappe/widgets/quick_list_widget.js:119 #: public/js/print_format_builder/print_format_builder.bundle.js:15 #: public/js/workflow_builder/workflow_builder.bundle.js:33 msgid "Save" @@ -21565,7 +21621,7 @@ msgstr "crwdns100180:0crwdne100180:0" msgid "Save Filter" msgstr "crwdns111194:0crwdne111194:0" -#: public/js/frappe/views/reports/query_report.js:1820 +#: public/js/frappe/views/reports/query_report.js:1805 msgid "Save Report" msgstr "crwdns100182:0crwdne100182:0" @@ -22689,7 +22745,7 @@ msgid "Set Filters" msgstr "crwdns100696:0crwdne100696:0" #: public/js/frappe/widgets/chart_widget.js:395 -#: public/js/frappe/widgets/quick_list_widget.js:102 +#: public/js/frappe/widgets/quick_list_widget.js:104 msgid "Set Filters for {0}" msgstr "crwdns100698:0{0}crwdne100698:0" @@ -22902,7 +22958,7 @@ msgstr "crwdns111218:0crwdne111218:0" msgid "Setup Approval Workflows" msgstr "crwdns100772:0crwdne100772:0" -#: public/js/frappe/views/reports/query_report.js:1690 +#: public/js/frappe/views/reports/query_report.js:1675 #: public/js/frappe/views/reports/report_view.js:1618 msgid "Setup Auto Email" msgstr "crwdns100774:0crwdne100774:0" @@ -24936,7 +24992,7 @@ msgid "The Client ID obtained from the Google Cloud Console under " msgstr "crwdns131442:0crwdne131442:0" -#: email/doctype/notification/notification.py:130 +#: email/doctype/notification/notification.py:131 msgid "The Condition '{0}' is invalid" msgstr "crwdns101636:0{0}crwdne101636:0" @@ -25390,7 +25446,7 @@ msgstr "crwdns131482:0crwdne131482:0" msgid "This goes above the slideshow." msgstr "crwdns131484:0crwdne131484:0" -#: public/js/frappe/views/reports/query_report.js:2027 +#: public/js/frappe/views/reports/query_report.js:2012 msgid "This is a background report. Please set the appropriate filters and then generate a new one." msgstr "crwdns101812:0crwdne101812:0" @@ -26249,6 +26305,10 @@ msgstr "crwdns131624:0crwdne131624:0" msgid "Tree" msgstr "crwdns131626:0crwdne131626:0" +#: public/js/frappe/list/base_list.js:211 +msgid "Tree View" +msgstr "crwdns142866:0crwdne142866:0" + #. Description of the 'Is Tree' (Check) field in DocType 'DocType' #: core/doctype/doctype/doctype.json msgid "Tree structures are implemented using Nested Set" @@ -26354,6 +26414,7 @@ msgstr "crwdns131640:0crwdne131640:0" #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: public/js/frappe/views/file/file_view.js:337 +#: public/js/frappe/widgets/widget_dialog.js:399 #: social/doctype/energy_point_log/energy_point_log.json #: website/doctype/web_template/web_template.json www/attribution.html:35 msgid "Type" @@ -26435,6 +26496,7 @@ msgstr "crwdns131652:0crwdne131652:0" #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: integrations/doctype/integration_request/integration_request.json #: integrations/doctype/webhook_request_log/webhook_request_log.json +#: public/js/frappe/widgets/widget_dialog.js:469 #: website/doctype/top_bar_item/top_bar_item.json #: website/doctype/website_slideshow_item/website_slideshow_item.json msgid "URL" @@ -27111,7 +27173,7 @@ msgid "User Permission" msgstr "crwdns102624:0crwdne102624:0" #: core/page/permission_manager/permission_manager_help.html:30 -#: public/js/frappe/views/reports/query_report.js:1804 +#: public/js/frappe/views/reports/query_report.js:1789 #: public/js/frappe/views/reports/report_view.js:1666 msgid "User Permissions" msgstr "crwdns102628:0crwdne102628:0" @@ -27429,7 +27491,7 @@ msgstr "crwdns131784:0crwdne131784:0" msgid "Value To Be Set" msgstr "crwdns131786:0crwdne131786:0" -#: model/base_document.py:965 model/document.py:682 +#: model/base_document.py:966 model/document.py:682 msgid "Value cannot be changed for {0}" msgstr "crwdns102750:0{0}crwdne102750:0" @@ -27472,7 +27534,7 @@ msgstr "crwdns102766:0{0}crwdne102766:0" msgid "Value to Validate" msgstr "crwdns131790:0crwdne131790:0" -#: model/base_document.py:1035 +#: model/base_document.py:1036 msgid "Value too big" msgstr "crwdns102770:0crwdne102770:0" @@ -27571,7 +27633,7 @@ msgid "View Full Log" msgstr "crwdns111324:0crwdne111324:0" #: public/js/frappe/views/treeview.js:463 -#: public/js/frappe/widgets/quick_list_widget.js:245 +#: public/js/frappe/widgets/quick_list_widget.js:247 msgid "View List" msgstr "crwdns102808:0crwdne102808:0" @@ -28453,7 +28515,7 @@ msgstr "crwdns127790:0crwdne127790:0" msgid "Write" msgstr "crwdns131894:0crwdne131894:0" -#: model/base_document.py:875 +#: model/base_document.py:876 msgid "Wrong Fetch From value" msgstr "crwdns103194:0crwdne103194:0" @@ -28540,7 +28602,7 @@ msgstr "crwdns131908:0crwdne131908:0" #: public/js/form_builder/utils.js:336 #: public/js/frappe/form/controls/link.js:475 #: public/js/frappe/list/list_sidebar_group_by.js:223 -#: public/js/frappe/views/reports/query_report.js:1541 +#: public/js/frappe/views/reports/query_report.js:1526 #: website/doctype/help_article/templates/help_article.html:25 msgid "Yes" msgstr "crwdns103238:0crwdne103238:0" @@ -29753,7 +29815,7 @@ msgstr "crwdns104008:0crwdne104008:0" msgid "via Google Meet" msgstr "crwdns132068:0crwdne132068:0" -#: email/doctype/notification/notification.py:215 +#: email/doctype/notification/notification.py:216 msgid "via Notification" msgstr "crwdns104012:0crwdne104012:0" @@ -29896,7 +29958,7 @@ msgstr "crwdns104080:0{0}crwdne104080:0" msgid "{0} Name" msgstr "crwdns104082:0{0}crwdne104082:0" -#: model/base_document.py:1065 +#: model/base_document.py:1066 msgid "{0} Not allowed to change {1} after submission from {2} to {3}" msgstr "crwdns104084:0{0}crwdnd104084:0{1}crwdnd104084:0{2}crwdnd104084:0{3}crwdne104084:0" @@ -29922,10 +29984,6 @@ msgstr "crwdns104088:0{0}crwdne104088:0" msgid "{0} Tree" msgstr "crwdns104090:0{0}crwdne104090:0" -#: public/js/frappe/list/base_list.js:209 -msgid "{0} View" -msgstr "crwdns104092:0{0}crwdne104092:0" - #: public/js/frappe/form/footer/form_timeline.js:126 #: public/js/frappe/form/sidebar/form_sidebar.js:86 msgid "{0} Web page views" @@ -30539,11 +30597,11 @@ msgstr "crwdns104370:0{0}crwdnd104370:0{1}crwdnd104370:0{2}crwdne104370:0" msgid "{0} {1} already exists" msgstr "crwdns104372:0{0}crwdnd104372:0{1}crwdne104372:0" -#: model/base_document.py:908 +#: model/base_document.py:909 msgid "{0} {1} cannot be \"{2}\". It should be one of \"{3}\"" msgstr "crwdns104374:0{0}crwdnd104374:0{1}crwdnd104374:0{2}crwdnd104374:0{3}crwdne104374:0" -#: utils/nestedset.py:337 +#: utils/nestedset.py:340 msgid "{0} {1} cannot be a leaf node as it has children" msgstr "crwdns104376:0{0}crwdnd104376:0{1}crwdne104376:0" @@ -30563,11 +30621,11 @@ msgstr "crwdns104382:0{0}crwdnd104382:0{1}crwdne104382:0" msgid "{0} {1}: Submitted Record cannot be deleted. You must {2} Cancel {3} it first." msgstr "crwdns104384:0{0}crwdnd104384:0{1}crwdnd104384:0{2}crwdnd104384:0{3}crwdne104384:0" -#: model/base_document.py:1026 +#: model/base_document.py:1027 msgid "{0}, Row {1}" msgstr "crwdns104386:0{0}crwdnd104386:0{1}crwdne104386:0" -#: model/base_document.py:1031 +#: model/base_document.py:1032 msgid "{0}: '{1}' ({3}) will get truncated, as max characters allowed is {2}" msgstr "crwdns104388:0{0}crwdnd104388:0{1}crwdnd104388:0{3}crwdnd104388:0{2}crwdne104388:0" @@ -30660,7 +30718,7 @@ msgid "{0}: fieldname cannot be set to reserved keyword {1}" msgstr "crwdns104430:0{0}crwdnd104430:0{1}crwdne104430:0" #: contacts/doctype/address/address.js:35 -#: contacts/doctype/contact/contact.js:83 +#: contacts/doctype/contact/contact.js:88 #: public/js/frappe/views/workspace/workspace.js:170 msgid "{0}: {1}" msgstr "crwdns104432:0{0}crwdnd104432:0{1}crwdne104432:0" diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po index 40911e214d..95d8b912b9 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: 2024-06-30 09:33+0000\n" -"PO-Revision-Date: 2024-07-02 15:49\n" +"PO-Revision-Date: 2024-07-07 15:47\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Swedish\n" "MIME-Version: 1.0\n" @@ -4354,7 +4354,7 @@ msgstr "Ändra" #: tests/test_translate.py:99 msgctxt "Coins" msgid "Change" -msgstr "Ändra" +msgstr "Växel" #. Label of the label (Data) field in DocType 'Customize Form' #: custom/doctype/customize_form/customize_form.json @@ -13048,7 +13048,7 @@ msgstr "Ogiltiga begäran argument" #: integrations/doctype/connected_app/connected_app.py:173 msgid "Invalid state." -msgstr "Ogiltig status." +msgstr "Ogiltigt tillstånd." #: core/doctype/data_import/importer.py:423 msgid "Invalid template file for import" @@ -28569,7 +28569,7 @@ msgstr "Arbetsflöde Tillstånd inte angiven" #: model/workflow.py:197 model/workflow.py:205 msgid "Workflow State transition not allowed from {0} to {1}" -msgstr "Arbetsflöde Övergång inte tillåten från {0} till {1}" +msgstr "Arbetsflöde Tillstånd Övergång inte tillåten från {0} till {1}" #: model/workflow.py:320 msgid "Workflow Status" @@ -30595,7 +30595,7 @@ msgstr "{0} måste börja och sluta med bokstav och får bara innehålla bokstä #: workflow/doctype/workflow/workflow.py:91 msgid "{0} not a valid State" -msgstr "{0} inte en giltig Tillstånd" +msgstr "{0} är inte giltig Tillstånd" #: model/rename_doc.py:380 msgid "{0} not allowed to be renamed" From 0199069cb279e4f098e216bd7d430627676146d1 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Thu, 11 Jul 2024 06:58:35 +0200 Subject: [PATCH 048/176] fix: cleanup user data on trash (#27068) --- frappe/core/doctype/user/user.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 96891b53e1..7eb2443598 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -536,6 +536,21 @@ class User(Document): # Delete EPS data frappe.db.delete("Energy Point Log", {"user": self.name}) + # Remove user link from Workflow Action + frappe.db.set_value("Workflow Action", {"user": self.name}, "user", None) + + # Delete user's List Filters + frappe.db.delete("List Filter", {"for_user": self.name}) + + # Remove user from Note's Seen By table + seen_notes = frappe.get_all("Note", filters=[["Note Seen By", "user", "=", self.name]], pluck="name") + for note_id in seen_notes: + note = frappe.get_doc("Note", note_id) + for row in note.seen_by: + if row.user == self.name: + note.remove(row) + note.save(ignore_permissions=True) + # Ask user to disable instead if document is still linked try: check_if_doc_is_linked(self) From fd9e80e364f37705374eac54afded5824f83b7d2 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Thu, 11 Jul 2024 07:18:19 +0200 Subject: [PATCH 049/176] feat: nudge for all DocTypes that can be disabled, not deleted (#27067) Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/core/doctype/user/user.py | 7 ------- frappe/model/delete_doc.py | 13 +++++++++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 7eb2443598..3269d2860e 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -17,7 +17,6 @@ from frappe.desk.doctype.notification_settings.notification_settings import ( toggle_notifications, ) from frappe.desk.notifications import clear_notifications -from frappe.model.delete_doc import check_if_doc_is_linked from frappe.model.document import Document from frappe.query_builder import DocType from frappe.rate_limiter import rate_limit @@ -551,12 +550,6 @@ class User(Document): note.remove(row) note.save(ignore_permissions=True) - # Ask user to disable instead if document is still linked - try: - check_if_doc_is_linked(self) - except frappe.LinkExistsError: - frappe.throw(_("You can disable the user instead of deleting it."), frappe.LinkExistsError) - def before_rename(self, old_name, new_name, merge=False): # if merging, delete the old user notification settings if merge: diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index 3d83af16b7..c1c8f2cb70 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -127,8 +127,17 @@ def delete_doc( # check if links exist if not force: - check_if_doc_is_linked(doc) - check_if_doc_is_dynamically_linked(doc) + try: + check_if_doc_is_linked(doc) + check_if_doc_is_dynamically_linked(doc) + except frappe.LinkExistsError as e: + if doc.meta.has_field("enabled") or doc.meta.has_field("disabled"): + frappe.throw( + _("You can disable this {0} instead of deleting it.").format(_(doctype)), + frappe.LinkExistsError, + ) + else: + raise e update_naming_series(doc) delete_from_table(doctype, name, ignore_doctypes, doc) From b47c31b054ac0af358dff3b673d40210268c7fd8 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Thu, 11 Jul 2024 13:19:38 +0530 Subject: [PATCH 050/176] fix: formatting Signed-off-by: Akhil Narang --- .../system_health_report/system_health_report.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/desk/doctype/system_health_report/system_health_report.py b/frappe/desk/doctype/system_health_report/system_health_report.py index 25a42e111c..abdc1b0272 100644 --- a/frappe/desk/doctype/system_health_report/system_health_report.py +++ b/frappe/desk/doctype/system_health_report/system_health_report.py @@ -186,7 +186,7 @@ class SystemHealthReport(Document): # Exclude "maybe" curently executing job upper_threshold = add_to_date(None, minutes=-30, as_datetime=True) self.scheduler_status = get_scheduler_status().get("status") - + mariadb_query = """ SELECT scheduled_job_type, AVG(CASE WHEN status != 'Complete' THEN 1 ELSE 0 END) * 100 AS failure_rate @@ -198,10 +198,10 @@ class SystemHealthReport(Document): GROUP BY scheduled_job_type HAVING failure_rate > 0 ORDER BY failure_rate DESC - LIMIT 5 + LIMIT 5 """ - postgres_query = """ + postgres_query = """ SELECT scheduled_job_type, AVG(CASE WHEN status != 'Complete' THEN 1 ELSE 0 END) * 100 AS "failure_rate" FROM "tabScheduled Job Log" @@ -214,8 +214,8 @@ class SystemHealthReport(Document): ORDER BY "failure_rate" DESC LIMIT 5 """ - - failing_jobs = frappe.db.multisql( + + failing_jobs = frappe.db.multisql( { "mariadb": mariadb_query, "postgres": postgres_query, From e3ab364af1b8cfa7b249b3ba84542d986eaa952c Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 11 Jul 2024 14:23:22 +0530 Subject: [PATCH 051/176] fix: show escaped content for Code fields --- frappe/public/js/frappe/list/list_view.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 7333a22281..1acd6b1347 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -784,9 +784,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { } const format = () => { - if (df.fieldtype === "Code") { - return value; - } else if (df.fieldtype === "Percent") { + if (df.fieldtype === "Percent") { return `
${_value} `; - } else if ( - ["Text Editor", "Text", "Small Text", "HTML Editor", "Markdown Editor"].includes( - df.fieldtype - ) - ) { + } else if (frappe.model.html_fieldtypes.includes(df.fieldtype)) { html = ` ${_value} `; From 1ba9e64b556cd0fbddee0688aca7c95ceb0684d6 Mon Sep 17 00:00:00 2001 From: GOPIKRISHNAN Date: Thu, 11 Jul 2024 15:25:07 +0530 Subject: [PATCH 052/176] fix: Fetch From, Need to Select Twice to Set Doctype (#27071) * Fixed - Fetch From, Need to Select Twice to Set Doctype By explicitly checking if (value), we ensure that doctype.value and fieldname.value are only updated when value is valid. This helps maintain a consistent state and prevents potential issues that could arise from attempting to destructure a null or undefined value * pre-commit run to format code --- .../js/form_builder/components/controls/FetchFromControl.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/form_builder/components/controls/FetchFromControl.vue b/frappe/public/js/form_builder/components/controls/FetchFromControl.vue index 1873a7b5d4..3afdaa69b7 100644 --- a/frappe/public/js/form_builder/components/controls/FetchFromControl.vue +++ b/frappe/public/js/form_builder/components/controls/FetchFromControl.vue @@ -63,7 +63,7 @@ let field_df = computedAsync(async () => { watch( () => props.value, (value) => { - [doctype.value, fieldname.value] = value?.split(".") || ["", ""]; + if (value) [doctype.value, fieldname.value] = value.split(".") || ["", ""]; }, { immediate: true } ); From 48a4e3a724cfbd379b839edb146cb95c74689357 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 16:55:19 +0200 Subject: [PATCH 053/176] fix: translation in onboarding_widget.js fix: translation in onboarding_widget.js --- frappe/public/js/frappe/widgets/onboarding_widget.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/widgets/onboarding_widget.js b/frappe/public/js/frappe/widgets/onboarding_widget.js index 4853c04b6a..bddb040df2 100644 --- a/frappe/public/js/frappe/widgets/onboarding_widget.js +++ b/frappe/public/js/frappe/widgets/onboarding_widget.js @@ -130,8 +130,8 @@ export default class OnboardingWidget extends Widget { } else { $( `` + step.action_label) || __(step.action) + }` ) .appendTo(this.step_footer) .on("click", () => actions[step.action](step)); @@ -139,8 +139,8 @@ export default class OnboardingWidget extends Widget { }; const set_description = () => { - let content = step.description - ? frappe.markdown(step.description) + let content = __(step.description) + ? frappe.markdown(__(step.description)) : `

${__(step.title)}

`; if (step.action === "Create Entry") { @@ -169,7 +169,7 @@ export default class OnboardingWidget extends Widget { $( `` ) .appendTo(this.step_footer) From 1cdec4351be120f9643d411e274943ea10a08299 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 16:38:21 +0200 Subject: [PATCH 054/176] fix: translation in chart_widget.js fix: translation in chart_widget.js --- frappe/public/js/frappe/widgets/chart_widget.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index 24d726ba85..db7553cc43 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -125,7 +125,7 @@ export default class ChartWidget extends Widget { if (this.chart_doc.type == "Heatmap") { filters = [ { - label: this.chart_settings.heatmap_year || this.chart_doc.heatmap_year, + label: __(this.chart_settings.heatmap_year) || __(this.chart_doc.heatmap_year), options: frappe.dashboard_utils.get_years_since_creation( frappe.boot.user.creation ), @@ -141,7 +141,7 @@ export default class ChartWidget extends Widget { } else { filters = [ { - label: this.chart_settings.time_interval || this.chart_doc.time_interval, + label: __(this.chart_settings.time_interval) || __(this.chart_doc.time_interval), options: ["Yearly", "Quarterly", "Monthly", "Weekly", "Daily"], icon: "calendar", class: "time-interval-filter", @@ -233,7 +233,7 @@ export default class ChartWidget extends Widget { df: { fieldtype: "DateRange", fieldname: "from_date", - placeholder: "Date Range", + placeholder: __("Date Range"), input_class: "input-xs", default: [this.chart_settings.from_date, this.chart_settings.to_date], value: [this.chart_settings.from_date, this.chart_settings.to_date], @@ -314,7 +314,7 @@ export default class ChartWidget extends Widget { if (this.chart_doc.document_type) { actions.push({ - label: __("{0} List", [this.chart_doc.document_type]), + label: __("{0} List", [__(this.chart_doc.document_type)]), action: "action-list", handler: () => { frappe.set_route("List", this.chart_doc.document_type); @@ -322,7 +322,7 @@ export default class ChartWidget extends Widget { }); } else if (this.chart_doc.chart_type === "Report") { actions.push({ - label: __("{0} Report", [this.chart_doc.report_name]), + label: __("{0} Report", [__(this.chart_doc.report_name)]), action: "action-list", handler: () => { frappe.set_route("query-report", this.chart_doc.report_name, this.filters); @@ -392,7 +392,7 @@ export default class ChartWidget extends Widget { setup_filter_dialog(fields) { let me = this; let dialog = new frappe.ui.Dialog({ - title: __("Set Filters for {0}", [this.chart_doc.chart_name]), + title: __("Set Filters for {0}", [__(this.chart_doc.chart_name)]), fields: fields, primary_action: function () { let values = this.get_values(); @@ -403,7 +403,7 @@ export default class ChartWidget extends Widget { me.fetch_and_update_chart(); } }, - primary_action_label: "Set", + primary_action_label: __("Set"), }); dialog.show(); @@ -473,7 +473,7 @@ export default class ChartWidget extends Widget { ${actions .map( (action) => - `
  • ${action.label}
  • ` + `
  • ${__(action.label)}
  • ` ) .join("")} From d9d9f335941e3d830615467ac0773ffcbfb59714 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:15:32 +0200 Subject: [PATCH 055/176] fix: translation in breadcrumbs.html fix: translation in breadcrumbs.html --- frappe/templates/includes/breadcrumbs.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/templates/includes/breadcrumbs.html b/frappe/templates/includes/breadcrumbs.html index 6e7d47cade..0c9f0484b3 100644 --- a/frappe/templates/includes/breadcrumbs.html +++ b/frappe/templates/includes/breadcrumbs.html @@ -14,7 +14,7 @@ {% endfor %} From a5c3592bd22f4dea9933e9c8f4051af8a46ffb6c Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:59:00 +0200 Subject: [PATCH 056/176] fix: translation in chart.js fix: translation in chart.js --- frappe/public/js/frappe/ui/chart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/ui/chart.js b/frappe/public/js/frappe/ui/chart.js index 642598c564..5307e631f9 100644 --- a/frappe/public/js/frappe/ui/chart.js +++ b/frappe/public/js/frappe/ui/chart.js @@ -33,7 +33,7 @@ frappe.ui.RealtimeChart = class RealtimeChart extends frappe.Chart { } else { this.currentSize++; } - this.addDataPoint(label, data); + this.addDataPoint(__(label), data); }; } }; From eb0349b7d31e51ec97caa3dbc5732fbb498c59fb Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:49:56 +0200 Subject: [PATCH 057/176] fix: translation in form_tour.js fix: translation in form_tour.js --- frappe/public/js/frappe/form/form_tour.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/form_tour.js b/frappe/public/js/frappe/form/form_tour.js index 94f37876bd..82933350de 100644 --- a/frappe/public/js/frappe/form/form_tour.js +++ b/frappe/public/js/frappe/form/form_tour.js @@ -11,8 +11,10 @@ frappe.ui.form.FormTour = class FormTour { padding: 10, overlayClickNext: true, keyboardControl: true, - nextBtnText: "Next", - prevBtnText: "Previous", + nextBtnText: __("Next"), + prevBtnText: __("Previous"), + doneBtnText: __("Done"), + closeBtnText: __("Close"), opacity: 0.25, onHighlighted: (step) => { // if last step is to save, then attach a listener to save button @@ -135,7 +137,7 @@ frappe.ui.form.FormTour = class FormTour { return { element, name, - popover: { title, description, position: frappe.router.slug(position || "Bottom") }, + popover: { title: __(title), description: __(description), position: frappe.router.slug(position || "Bottom") }, onNext: on_next, onPrevious: on_prev, }; From 2910ac65cb23ad2d356e99842f1ef876151c891b Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:19:40 +0200 Subject: [PATCH 058/176] fix: translation in document.py fix: translation in document.py --- frappe/model/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 01278775b3..9a0ea809bb 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -238,7 +238,7 @@ class Document(BaseDocument): def raise_no_permission_to(self, perm_type): """Raise `frappe.PermissionError`.""" frappe.flags.error_message = ( - _("Insufficient Permission for {0}").format(self.doctype) + f" ({frappe.bold(_(perm_type))})" + _("Insufficient Permission for {0}").format(_(self.doctype)) + f" ({frappe.bold(_(perm_type))})" ) raise frappe.PermissionError From ca6d8809e95373249b4e517a4a9e284e4f958eba Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:08:02 +0200 Subject: [PATCH 059/176] fix: translation in user_profile_controller.js fix: translation in user_profile_controller.js --- frappe/desk/page/user_profile/user_profile_controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/desk/page/user_profile/user_profile_controller.js b/frappe/desk/page/user_profile/user_profile_controller.js index fd38f09ddd..abf0bea297 100644 --- a/frappe/desk/page/user_profile/user_profile_controller.js +++ b/frappe/desk/page/user_profile/user_profile_controller.js @@ -77,7 +77,7 @@ class UserProfile { render_heatmap() { this.heatmap = new frappe.Chart(".performance-heatmap", { type: "heatmap", - countLabel: "Energy Points", + countLabel: __("Energy Points"), data: {}, discreteDomains: 1, radius: 3, @@ -111,7 +111,7 @@ class UserProfile { value_based_on: "points", chart_type: "Sum", document_type: "Energy Point Log", - name: "Energy Points", + name: __("Energy Points"), width: "half", based_on: "creation", }; From ac894ae560f9ff0c95287da37dafcb3e53718e78 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:03:42 +0200 Subject: [PATCH 060/176] fix: translation in load.py fix: translation in load.py --- frappe/desk/form/load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 9b01c8ecee..459904eb7d 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -38,7 +38,7 @@ def getdoc(doctype, name, user=None): if not doc.has_permission("read"): frappe.flags.error_message = _("Insufficient Permission for {0}").format( - frappe.bold(doctype + " " + name) + frappe.bold(_(doctype) + " " + _(name)) ) raise frappe.PermissionError(("read", doctype, name)) From 2f55f2c788d05d8bcd7e010763d059441eab5b0e Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sun, 23 Jun 2024 14:24:08 +0200 Subject: [PATCH 061/176] fix: translation in permission_manager.js fix: translation in permission_manager.js --- frappe/core/page/permission_manager/permission_manager.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/core/page/permission_manager/permission_manager.js b/frappe/core/page/permission_manager/permission_manager.js index 308bbfedba..8fd6f59f38 100644 --- a/frappe/core/page/permission_manager/permission_manager.js +++ b/frappe/core/page/permission_manager/permission_manager.js @@ -106,7 +106,7 @@ frappe.PermissionEngine = class PermissionEngine { reset_std_permissions(data) { let doctype = this.get_doctype(); - let d = frappe.confirm(__("Reset Permissions for {0}?", [doctype]), () => { + let d = frappe.confirm(__("Reset Permissions for {0}?", [__(doctype)]), () => { return frappe .call({ module: "frappe.core", @@ -122,7 +122,7 @@ frappe.PermissionEngine = class PermissionEngine { // show standard permissions let $d = $(d.wrapper) .find(".frappe-confirm-message") - .append("
    Standard Permissions:

    "); + .append("
    ${__("Standard Permissions")}:

    "); let $wrapper = $("

    ").appendTo($d); data.message.forEach((d) => { let rights = this.rights @@ -134,7 +134,7 @@ frappe.PermissionEngine = class PermissionEngine { d.rights = rights.join(", "); $wrapper.append(`
    \ -
    ${d.role}, Level ${d.permlevel || 0}
    \ +
    ${__(d.role)}, ${__("Level")} ${d.permlevel || 0}
    \
    ${d.rights}
    \

    `); }); From 30e67ef3f2bfaf901116b01e24d989f5de2cb4a2 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 11 Jul 2024 14:35:38 +0200 Subject: [PATCH 062/176] fix: email record linking --- frappe/core/doctype/communication/communication.py | 11 +++++++---- .../core/doctype/communication/test_communication.py | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index b10a7235e1..ed1409575c 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -605,16 +605,19 @@ def parse_email(email_strings): user, detail = None, None if "+" in local_part: user, detail = local_part.split("+", 1) - if "--" in local_part: + elif "--" in local_part: detail, user = local_part.rsplit("--", 1) + if not detail: + continue + document_parts = None - if detail and "=" in detail: + if "=" in detail: document_parts = detail.split("=", 1) - elif detail and "+" in detail: + elif "+" in detail: document_parts = detail.split("+", 1) - if not document_parts or not len(document_parts) != 2: + if not document_parts or len(document_parts) != 2: continue doctype = unquote_plus(document_parts[0]) diff --git a/frappe/core/doctype/communication/test_communication.py b/frappe/core/doctype/communication/test_communication.py index 3d42c823c5..40af4053ad 100644 --- a/frappe/core/doctype/communication/test_communication.py +++ b/frappe/core/doctype/communication/test_communication.py @@ -221,11 +221,12 @@ class TestCommunication(FrappeTestCase): def test_parse_email(self): to = "Jon Doe " cc = """=?UTF-8?Q?Max_Mu=C3=9F?= , - erp+Customer+that%20company@example.org""" + erp+Customer=Plus%2BCompany@example.org, + erp+Customer+Space%20Company@example.org""" bcc = "" results = list(parse_email([to, cc, bcc])) - self.assertEqual([("Customer", "that company")], results) + self.assertEqual([("Customer", "Plus+Company"), ("Customer", "Space Company")], results) results = list(parse_email([to, bcc])) self.assertEqual(results, []) From b193cde7c03cdbe928c9cf2ba24e0ebe447396bb Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Thu, 11 Jul 2024 19:11:29 +0530 Subject: [PATCH 063/176] feat: allow creating `Days Before / After` notifications for child table (#26982) --- .../doctype/notification/notification.js | 36 +++++++------- .../doctype/notification/notification.json | 13 +++-- .../doctype/notification/notification.py | 48 ++++++++++++------- 3 files changed, 56 insertions(+), 41 deletions(-) diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js index b88d10ea0d..bede0b429b 100644 --- a/frappe/email/doctype/notification/notification.js +++ b/frappe/email/doctype/notification/notification.js @@ -1,6 +1,8 @@ // Copyright (c) 2018, Frappe Technologies and contributors // For license information, please see license.txt +const DATE_BASED_EVENTS = ["Days Before", "Days After"]; + frappe.notification = { setup_fieldname_select: function (frm) { // get the doctype to update fields @@ -129,6 +131,8 @@ Last comment: {{ comments[-1].comment }} by {{ comments[-1].by }} frappe.ui.form.on("Notification", { onload: function (frm) { frm.set_query("document_type", function () { + if (DATE_BASED_EVENTS.includes(frm.doc.event)) return; + return { filters: { istable: 0, @@ -166,23 +170,23 @@ frappe.ui.form.on("Notification", { frappe.set_route("Form", "Customize Form"); }, event: function (frm) { - if (["Days Before", "Days After"].includes(frm.doc.event)) { - frm.add_custom_button(__("Get Alerts for Today"), function () { - frappe.call({ - method: "frappe.email.doctype.notification.notification.get_documents_for_today", - args: { - notification: frm.doc.name, - }, - callback: function (r) { - if (r.message && r.message.length > 0) { - frappe.msgprint(r.message.toString()); - } else { - frappe.msgprint(__("No alerts for today")); - } - }, - }); + if (!DATE_BASED_EVENTS.includes(frm.doc.event) || frm.is_new()) return; + + frm.add_custom_button(__("Get Alerts for Today"), function () { + frappe.call({ + method: "frappe.email.doctype.notification.notification.get_documents_for_today", + args: { + notification: frm.doc.name, + }, + callback: function (r) { + if (r.message && r.message.length > 0) { + frappe.msgprint(r.message.toString()); + } else { + frappe.msgprint(__("No alerts for today")); + } + }, }); - } + }); }, channel: function (frm) { frm.toggle_reqd("recipients", frm.doc.channel == "Email"); diff --git a/frappe/email/doctype/notification/notification.json b/frappe/email/doctype/notification/notification.json index b50c8d8468..c05ea05b01 100644 --- a/frappe/email/doctype/notification/notification.json +++ b/frappe/email/doctype/notification/notification.json @@ -8,16 +8,16 @@ "engine": "InnoDB", "field_order": [ "enabled", + "is_standard", + "module", "column_break_2", "channel", "slack_webhook_url", "filters", "subject", - "document_type", - "is_standard", - "module", - "col_break_1", "event", + "document_type", + "col_break_1", "method", "date_changed", "days_in_advance", @@ -119,7 +119,6 @@ "fieldtype": "Column Break" }, { - "depends_on": "eval: doc.document_type", "fieldname": "event", "fieldtype": "Select", "in_list_view": 1, @@ -292,7 +291,7 @@ "icon": "fa fa-envelope", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-17 04:03:22.591781", + "modified": "2024-07-04 05:53:40.595130", "modified_by": "Administrator", "module": "Email", "name": "Notification", @@ -315,4 +314,4 @@ "states": [], "title_field": "subject", "track_changes": 1 -} +} \ No newline at end of file diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index 72c95cf194..c9e9f44a53 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -18,6 +18,8 @@ from frappe.utils.jinja import validate_template from frappe.utils.safe_exec import get_safe_globals FORMATS = {"HTML": ".html", "Markdown": ".md", "Plain Text": ".txt"} +FORBIDDEN_DOCUMENT_TYPES = frozenset(("Email Queue",)) +DATE_BASED_EVENTS = frozenset(("Days Before", "Days After")) class Notification(Document): @@ -27,9 +29,7 @@ class Notification(Document): from typing import TYPE_CHECKING if TYPE_CHECKING: - from frappe.email.doctype.notification_recipient.notification_recipient import ( - NotificationRecipient, - ) + from frappe.email.doctype.notification_recipient.notification_recipient import NotificationRecipient from frappe.types import DF attach_print: DF.Check @@ -90,7 +90,7 @@ class Notification(Document): if self.event == "Value Change" and not self.value_changed: frappe.throw(_("Please specify which value field must be checked")) - self.validate_forbidden_types() + self.validate_forbidden_document_types() self.validate_condition() self.validate_standard() frappe.cache.hdel("notifications", self.document_type) @@ -130,12 +130,16 @@ def get_context(context): except Exception: frappe.throw(_("The Condition '{0}' is invalid").format(self.condition)) - def validate_forbidden_types(self): - forbidden_document_types = ("Email Queue",) - if self.document_type in forbidden_document_types or frappe.get_meta(self.document_type).istable: - # currently notifications don't work on child tables as events are not fired for each record of child table - - frappe.throw(_("Cannot set Notification on Document Type {0}").format(self.document_type)) + def validate_forbidden_document_types(self): + if self.document_type in FORBIDDEN_DOCUMENT_TYPES or ( + frappe.get_meta(self.document_type).istable and self.event not in DATE_BASED_EVENTS + ): + # only date based events are allowed for child tables + frappe.throw( + _("Cannot set Notification with event {0} on Document Type {1}").format( + _(self.event), _(self.document_type) + ) + ) def get_documents_for_today(self): """get list of documents that will be triggered today""" @@ -237,8 +241,8 @@ def get_context(context): notification_doc = { "type": "Alert", - "document_type": doc.doctype, - "document_name": doc.name, + "document_type": get_reference_doctype(doc), + "document_name": get_reference_name(doc), "subject": subject, "from_user": doc.modified_by or doc.owner, "email_content": frappe.render_template(self.message, context), @@ -270,8 +274,8 @@ def get_context(context): # No need to add if it is already a communication. if doc.doctype != "Communication": communication = make_communication( - doctype=doc.doctype, - name=doc.name, + doctype=get_reference_doctype(doc), + name=get_reference_name(doc), content=message, subject=subject, sender=sender, @@ -294,8 +298,8 @@ def get_context(context): cc=cc, bcc=bcc, message=message, - reference_doctype=doc.doctype, - reference_name=doc.name, + reference_doctype=get_reference_doctype(doc), + reference_name=get_reference_name(doc), attachments=attachments, expose_recipients="header", print_letterhead=((attachments and attachments[0].get("print_letterhead")) or False), @@ -306,8 +310,8 @@ def get_context(context): send_slack_message( webhook_url=self.slack_webhook_url, message=frappe.render_template(self.message, context), - reference_doctype=doc.doctype, - reference_name=doc.name, + reference_doctype=get_reference_doctype(doc), + reference_name=get_reference_name(doc), ) def send_sms(self, doc, context): @@ -543,3 +547,11 @@ def get_emails_from_template(template, context): emails = frappe.render_template(template, context) if "{" in template else template return filter(None, emails.replace(",", "\n").split("\n")) + + +def get_reference_doctype(doc): + return doc.parenttype if doc.meta.istable else doc.doctype + + +def get_reference_name(doc): + return doc.parent if doc.meta.istable else doc.name From d0f7760431f7dacbcda901ccd84bbf1672384d40 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Fri, 12 Jul 2024 09:09:06 +0200 Subject: [PATCH 064/176] fix: translation in dashboard_chart.js (#26898) fix: translation in dashboard_chart.js --- frappe/desk/doctype/dashboard_chart/dashboard_chart.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index 31fb7e5167..e11d496d69 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -397,7 +397,7 @@ frappe.ui.form.on("Dashboard Chart", { } } }, - primary_action_label: "Set", + primary_action_label: __("Set"), }); frappe.dashboards.filters_dialog = dialog; @@ -484,7 +484,7 @@ frappe.ui.form.on("Dashboard Chart", { } frm.trigger("set_dynamic_filters_in_table"); }, - primary_action_label: "Set", + primary_action_label: __("Set"), }); dialog.show(); From 57a9cc4721ae5655928604c47491d6753d0f248c Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Fri, 12 Jul 2024 09:09:32 +0200 Subject: [PATCH 065/176] fix: translation in number_card.js (#26899) fix: translation in number_card.js --- frappe/desk/doctype/number_card/number_card.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/desk/doctype/number_card/number_card.js b/frappe/desk/doctype/number_card/number_card.js index ef04ac5b3e..274ca76848 100644 --- a/frappe/desk/doctype/number_card/number_card.js +++ b/frappe/desk/doctype/number_card/number_card.js @@ -33,7 +33,7 @@ frappe.ui.form.on("Number Card", { }, create_add_to_dashboard_button: function (frm) { - frm.add_custom_button("Add Card to Dashboard", () => { + frm.add_custom_button(__("Add Card to Dashboard"), () => { const dialog = frappe.dashboard_utils.get_add_to_dashboard_dialog( frm.doc.name, "Number Card", @@ -292,7 +292,7 @@ frappe.ui.form.on("Number Card", { frm.trigger("render_filters_table"); } }, - primary_action_label: "Set", + primary_action_label: __("Set"), }); if (is_document_type) { @@ -384,7 +384,7 @@ frappe.ui.form.on("Number Card", { } frm.trigger("set_dynamic_filters_in_table"); }, - primary_action_label: "Set", + primary_action_label: __("Set"), }); dialog.show(); From fd3502f8f4b5bac3cee31983d08a0b65a3f775aa Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Fri, 12 Jul 2024 12:50:21 +0530 Subject: [PATCH 066/176] fix: send 2FA OTP email synchronously --- frappe/templates/includes/login/login.js | 2 +- frappe/twofactor.py | 30 ++++++------------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js index e4db68aba0..427e4c3ee6 100644 --- a/frappe/templates/includes/login/login.js +++ b/frappe/templates/includes/login/login.js @@ -329,7 +329,7 @@ var request_otp = function (r) { $('.login-content:visible').append( `
    -
    +
    {{ _("Verification") | e }}
    diff --git a/frappe/twofactor.py b/frappe/twofactor.py index b5ddd080f0..9e60bd6a18 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -344,30 +344,14 @@ def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, mess hotp = pyotp.HOTP(otp_secret) otp = hotp.at(int(token)) template_args = {"otp": otp, "otp_issuer": otp_issuer} - if not subject: - subject = get_email_subject_for_2fa(template_args) - if not message: - message = get_email_body_for_2fa(template_args) - email_args = { - "recipients": user_email, - "sender": None, - "subject": subject, - "message": message, - "header": [_("Verfication Code"), "blue"], - "delayed": False, - "retry": 3, - } - - enqueue( - method=frappe.sendmail, - queue="short", - timeout=300, - event=None, - is_async=True, - job_name=None, - now=False, - **email_args, + frappe.sendmail( + recipients=user_email, + subject=subject or get_email_subject_for_2fa(template_args), + message=message or get_email_body_for_2fa(template_args), + header=[_("Verfication Code"), "blue"], + delayed=False, + retry=3, ) return True From b00efb06c0c34133e8055aa4ce926ce191dca39b Mon Sep 17 00:00:00 2001 From: David Arnold Date: Sun, 4 Feb 2024 12:20:10 +0100 Subject: [PATCH 067/176] feat: generalize receiver logic in notifications --- .../doctype/notification/notification.js | 39 ++++++----- .../doctype/notification/notification.py | 67 +++++++++++++++---- 2 files changed, 74 insertions(+), 32 deletions(-) diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js index bede0b429b..6f628b117a 100644 --- a/frappe/email/doctype/notification/notification.js +++ b/frappe/email/doctype/notification/notification.js @@ -14,10 +14,11 @@ frappe.notification = { let get_select_options = function (df, parent_field) { // Append parent_field name along with fieldname for child table fields let select_value = parent_field ? df.fieldname + "," + parent_field : df.fieldname; + let path = parent_field ? parent_field + " > " + df.fieldname : df.fieldname; return { value: select_value, - label: df.fieldname + " (" + __(df.label, null, df.parent) + ")", + label: path + " (" + __(df.label, null, df.parent) + ")", }; }; @@ -49,28 +50,30 @@ frappe.notification = { frm.set_df_property("date_changed", "options", get_date_change_options()); let receiver_fields = []; - if (frm.doc.channel === "Email") { - receiver_fields = $.map(fields, function (d) { - // Add User and Email fields from child into select dropdown - if (frappe.model.table_fields.includes(d.fieldtype)) { - let child_fields = frappe.get_doc("DocType", d.options).fields; - return $.map(child_fields, function (df) { - return df.options == "Email" || - (df.options == "User" && df.fieldtype == "Link") - ? get_select_options(df, d.fieldname) - : null; + let find_receiver_fields = function (extra) { + let predicate = function (df) { + return extra(df) || (df.options == "User" && df.fieldtype == "Link"); + }; + let extract = function (df) { + // Add recipients from child doctypes into select dropdown + if (frappe.model.table_fields.includes(df.fieldtype)) { + let child_fields = frappe.get_doc("DocType", df.options).fields; + return $.map(child_fields, function (cdf) { + return predicate(cdf) ? get_select_options(cdf, df.fieldname) : null; }); - // Add User and Email fields from parent into select dropdown } else { - return d.options == "Email" || - (d.options == "User" && d.fieldtype == "Link") - ? get_select_options(d) - : null; + return predicate(df) ? get_select_options(df) : null; } + }; + return $.map(fields, extract); + }; + if (frm.doc.channel === "Email") { + receiver_fields = find_receiver_fields(function (df) { + return df.options == "Email"; }); } else if (["WhatsApp", "SMS"].includes(frm.doc.channel)) { - receiver_fields = $.map(fields, function (d) { - return d.options == "Phone" ? get_select_options(d) : null; + receiver_fields = find_receiver_fields(function (df) { + return df.options == "Phone" || df.options == "Mobile"; }); } diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index c9e9f44a53..bae12191fd 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -176,7 +176,7 @@ def get_context(context): """Build recipients and send Notification""" context = get_context(doc) - context = {"doc": doc, "alert": self, "comments": None} + context.update({"alert": self, "comments": None}) if doc.get("_comments"): context["comments"] = json.loads(doc.get("_comments")) @@ -315,8 +315,27 @@ def get_context(context): ) def send_sms(self, doc, context): + def get_phone_no(d, field): + option = d.meta.get_field(field).options.strip() + if option == "Phone" or option == "Mobile": + phone_no = d.get(field) + if not phone_no: + self.log_error(_("Field {0} on document {1} has no Mobile No set").format(field, d.name)) + elif option == "User": + user = d.get(field) + phone_no = frappe.get_value("User", user, "mobile_no") + if not phone_no: + self.log_error(_("User {0} has no Mobile No set").format(user)) + else: + frappe.throw( + _("Field {0} on document {1} is neither a Mobile No data field nor a User link").format( + field, d.name + ) + ) + return phone_no + send_sms( - receiver_list=self.get_receiver_list(doc, context), + receiver_list=self.get_receiver_list(doc, context, "mobile_no", get_phone_no), msg=frappe.utils.strip_html_tags(frappe.render_template(self.message, context)), ) @@ -329,16 +348,17 @@ def get_context(context): if not frappe.safe_eval(recipient.condition, None, context): continue if recipient.receiver_by_document_field: - fields = recipient.receiver_by_document_field.split(",") - # fields from child table - if len(fields) > 1: - for d in doc.get(fields[1]): - email_id = d.get(fields[0]) + data_field, child_field = _parse_receiver_by_document_field( + recipient.receiver_by_document_field + ) + if child_field: + for d in doc.get(child_field): + email_id = d.get(data_field) if validate_email_address(email_id): recipients.append(email_id) - # field from parent doc + # field from current doc else: - email_ids_value = doc.get(fields[0]) + email_ids_value = doc.get(data_field) if validate_email_address(email_ids_value): email_ids = email_ids_value.replace(",", "\n") recipients = recipients + email_ids.split("\n") @@ -358,7 +378,7 @@ def get_context(context): return list(set(recipients)), list(set(cc)), list(set(bcc)) - def get_receiver_list(self, doc, context): + def get_receiver_list(self, doc, context, user_field, field_extractor_func): """return receiver list based on the doc field and role specified""" receiver_list = [] for recipient in self.recipients: @@ -368,18 +388,28 @@ def get_context(context): # For sending messages to the owner's mobile phone number if recipient.receiver_by_document_field == "owner": - receiver_list += get_user_info([dict(user_name=doc.get("owner"))], "mobile_no") + receiver_list += get_user_info([dict(user_name=doc.get("owner"))], user_field) # For sending messages to the number specified in the receiver field elif recipient.receiver_by_document_field: - receiver_list.append(doc.get(recipient.receiver_by_document_field)) + data_field, child_field = _parse_receiver_by_document_field( + recipient.receiver_by_document_field + ) + if child_field: + for d in doc.get(child_field): + if recv := field_extractor_func(d, data_field): + receiver_list.append(recv) + # field from current doc + else: + if recv := field_extractor_func(doc, data_field): + receiver_list.append(recv) # For sending messages to specified role if recipient.receiver_by_role: receiver_list += get_info_based_on_role( - recipient.receiver_by_role, "mobile_no", ignore_permissions=True + recipient.receiver_by_role, user_field, ignore_permissions=True ) - return receiver_list + return list(set(receiver_list)) def get_attachment(self, doc): """check print settings are attach the pdf""" @@ -555,3 +585,12 @@ def get_reference_doctype(doc): def get_reference_name(doc): return doc.parent if doc.meta.istable else doc.name + +def _parse_receiver_by_document_field(s): + fragments = s.split(",") + # fields from child table or linked doctype + if len(fragments) > 1: + data_field, child_field = fragments + else: + data_field, child_field = fragments[0], None + return data_field, child_field From 19e03592be807113d0fbf590e7126acd671cfb40 Mon Sep 17 00:00:00 2001 From: David Arnold Date: Mon, 12 Feb 2024 15:40:10 +0100 Subject: [PATCH 068/176] style: be more explicit and docstring --- .../doctype/notification/notification.js | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js index 6f628b117a..d224faf3ca 100644 --- a/frappe/email/doctype/notification/notification.js +++ b/frappe/email/doctype/notification/notification.js @@ -35,6 +35,37 @@ frappe.notification = { ]); }; + let get_receiver_fields = function ( + is_extra_receiver_field = (_) => { + return false; + } + ) { + // finds receiver fields from the fields or any child table + // by default finds any link to the User doctype + // however an additional optional predicate can be passed as argument + // to find additional fields + let is_receiver_field = function (df) { + return ( + is_extra_receiver_field(df) || + (df.options == "User" && df.fieldtype == "Link") + ); + }; + let extract_receiver_field = function (df) { + // Add recipients from child doctypes into select dropdown + if (frappe.model.table_fields.includes(df.fieldtype)) { + let child_fields = frappe.get_doc("DocType", df.options).fields; + return $.map(child_fields, function (cdf) { + return is_receiver_field(cdf) + ? get_select_options(cdf, df.fieldname) + : null; + }); + } else { + return is_receiver_field(df) ? get_select_options(df) : null; + } + }; + return $.map(fields, extract_receiver_field); + }; + let fields = frappe.get_doc("DocType", frm.doc.document_type).fields; let options = $.map(fields, function (d) { return frappe.model.no_value_type.includes(d.fieldtype) @@ -50,30 +81,13 @@ frappe.notification = { frm.set_df_property("date_changed", "options", get_date_change_options()); let receiver_fields = []; - let find_receiver_fields = function (extra) { - let predicate = function (df) { - return extra(df) || (df.options == "User" && df.fieldtype == "Link"); - }; - let extract = function (df) { - // Add recipients from child doctypes into select dropdown - if (frappe.model.table_fields.includes(df.fieldtype)) { - let child_fields = frappe.get_doc("DocType", df.options).fields; - return $.map(child_fields, function (cdf) { - return predicate(cdf) ? get_select_options(cdf, df.fieldname) : null; - }); - } else { - return predicate(df) ? get_select_options(df) : null; - } - }; - return $.map(fields, extract); - }; if (frm.doc.channel === "Email") { - receiver_fields = find_receiver_fields(function (df) { + receiver_fields = get_receiver_fields(fields, function (df) { return df.options == "Email"; }); } else if (["WhatsApp", "SMS"].includes(frm.doc.channel)) { - receiver_fields = find_receiver_fields(function (df) { - return df.options == "Phone" || df.options == "Mobile"; + receiver_fields = get_receiver_fields(fields, function (df) { + df.options == "Phone" || df.options == "Mobile"; }); } From f0a28b51ee3d051be876ecc18da2762996ff15f1 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 17 Jun 2024 09:38:44 +0200 Subject: [PATCH 069/176] fix: add customer to eligible indirections --- frappe/email/doctype/notification/notification.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index bae12191fd..1b2ecb536b 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -326,11 +326,16 @@ def get_context(context): phone_no = frappe.get_value("User", user, "mobile_no") if not phone_no: self.log_error(_("User {0} has no Mobile No set").format(user)) + elif option == "Customer": + customer = d.get(field) + phone_no = frappe.get_value("Customer", customer, "mobile_no") + if not phone_no: + self.log_error(_("Customer {0} has no Mobile No set").format(customer)) else: frappe.throw( - _("Field {0} on document {1} is neither a Mobile No data field nor a User link").format( - field, d.name - ) + _( + "Field {0} on document {1} is neither a Mobile No data field nor a Customer or User link" + ).format(field, d.name) ) return phone_no From 69ac3b7f1669a2f18f73b27e63c46151631f116c Mon Sep 17 00:00:00 2001 From: David Date: Mon, 17 Jun 2024 10:12:43 +0200 Subject: [PATCH 070/176] fix: add customer to eligible indirections 2 --- frappe/email/doctype/notification/notification.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js index d224faf3ca..4017c9e40f 100644 --- a/frappe/email/doctype/notification/notification.js +++ b/frappe/email/doctype/notification/notification.js @@ -34,8 +34,8 @@ frappe.notification = { { value: "modified", label: `modified (${__("Last Modified Date")})` }, ]); }; - let get_receiver_fields = function ( + fields, is_extra_receiver_field = (_) => { return false; } @@ -47,7 +47,8 @@ frappe.notification = { let is_receiver_field = function (df) { return ( is_extra_receiver_field(df) || - (df.options == "User" && df.fieldtype == "Link") + (df.options == "User" && df.fieldtype == "Link") || + (df.options == "Customer" && df.fieldtype == "Link") ); }; let extract_receiver_field = function (df) { From c4da76579c9c1994aa0baf131996854ff2af520d Mon Sep 17 00:00:00 2001 From: David Date: Fri, 21 Jun 2024 12:35:17 +0200 Subject: [PATCH 071/176] fix: error log context on notification failure --- frappe/email/doctype/notification/notification.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index 1b2ecb536b..906152f7a6 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -320,17 +320,21 @@ def get_context(context): if option == "Phone" or option == "Mobile": phone_no = d.get(field) if not phone_no: - self.log_error(_("Field {0} on document {1} has no Mobile No set").format(field, d.name)) + doc.log_error( + _("Notification: field {0} on document {1} has no Mobile No set").format( + field, d.name + ) + ) elif option == "User": user = d.get(field) phone_no = frappe.get_value("User", user, "mobile_no") if not phone_no: - self.log_error(_("User {0} has no Mobile No set").format(user)) + doc.log_error(_("Notification: user {0} has no Mobile No set").format(user)) elif option == "Customer": customer = d.get(field) phone_no = frappe.get_value("Customer", customer, "mobile_no") if not phone_no: - self.log_error(_("Customer {0} has no Mobile No set").format(customer)) + doc.log_error(_("Notification: customer {0} has no Mobile No set").format(customer)) else: frappe.throw( _( From 7c1abdf1aaebd70ebbe3e47a750ae9df13c95f8b Mon Sep 17 00:00:00 2001 From: David Date: Mon, 1 Jul 2024 19:18:04 +0200 Subject: [PATCH 072/176] fix: implement feedback --- .../doctype/notification/notification.py | 73 ++++++++++--------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index 906152f7a6..ae915759c0 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -315,39 +315,42 @@ def get_context(context): ) def send_sms(self, doc, context): - def get_phone_no(d, field): - option = d.meta.get_field(field).options.strip() - if option == "Phone" or option == "Mobile": - phone_no = d.get(field) - if not phone_no: - doc.log_error( - _("Notification: field {0} on document {1} has no Mobile No set").format( - field, d.name - ) - ) - elif option == "User": - user = d.get(field) - phone_no = frappe.get_value("User", user, "mobile_no") - if not phone_no: - doc.log_error(_("Notification: user {0} has no Mobile No set").format(user)) - elif option == "Customer": - customer = d.get(field) - phone_no = frappe.get_value("Customer", customer, "mobile_no") - if not phone_no: - doc.log_error(_("Notification: customer {0} has no Mobile No set").format(customer)) - else: - frappe.throw( - _( - "Field {0} on document {1} is neither a Mobile No data field nor a Customer or User link" - ).format(field, d.name) - ) - return phone_no - send_sms( - receiver_list=self.get_receiver_list(doc, context, "mobile_no", get_phone_no), + receiver_list=self.get_receiver_list(doc, context, "mobile_no", self.get_mobile_no), msg=frappe.utils.strip_html_tags(frappe.render_template(self.message, context)), ) + @staticmethod + def get_mobile_no(doc, field): + option = doc.meta.get_field(field).options.strip() + # users may sometimes register mobile numbers under Phone type fields + if option == "Phone" or option == "Mobile": + mobile_no = doc.get(field) + if not mobile_no: + doc.log_error( + _("Notification: document {0} has no {1} number set (field: {2})").format( + field, doc.name, option, field + ) + ) + # but on user & customer it's expected to be set on the proper field + elif option == "User": + user = doc.get(field) + mobile_no = frappe.get_value("User", user, "mobile_no") + if not mobile_no: + doc.log_error(_("Notification: user {0} has no Mobile number set").format(user)) + elif option == "Customer": + customer = doc.get(field) + mobile_no = frappe.get_value("Customer", customer, "mobile_no") + if not mobile_no: + doc.log_error(_("Notification: customer {0} has no Mobile number set").format(customer)) + else: + frappe.throw( + _( + "Field {0} on document {1} is neither a Mobile number field nor a Customer or User link" + ).format(field, doc.name) + ) + return mobile_no + def get_list_of_recipients(self, doc, context): recipients = [] cc = [] @@ -387,8 +390,10 @@ def get_context(context): return list(set(recipients)), list(set(cc)), list(set(bcc)) - def get_receiver_list(self, doc, context, user_field, field_extractor_func): + def get_receiver_list(self, doc, context, field_on_user="mobile_no", recipient_extractor_func=None): """return receiver list based on the doc field and role specified""" + if not recipient_extractor_func: + recipient_extractor_func = self.get_mobile_no receiver_list = [] for recipient in self.recipients: if recipient.condition: @@ -397,7 +402,7 @@ def get_context(context): # For sending messages to the owner's mobile phone number if recipient.receiver_by_document_field == "owner": - receiver_list += get_user_info([dict(user_name=doc.get("owner"))], user_field) + receiver_list += get_user_info([dict(user_name=doc.get("owner"))], field_on_user) # For sending messages to the number specified in the receiver field elif recipient.receiver_by_document_field: data_field, child_field = _parse_receiver_by_document_field( @@ -405,17 +410,17 @@ def get_context(context): ) if child_field: for d in doc.get(child_field): - if recv := field_extractor_func(d, data_field): + if recv := recipient_extractor_func(d, data_field): receiver_list.append(recv) # field from current doc else: - if recv := field_extractor_func(doc, data_field): + if recv := recipient_extractor_func(doc, data_field): receiver_list.append(recv) # For sending messages to specified role if recipient.receiver_by_role: receiver_list += get_info_based_on_role( - recipient.receiver_by_role, user_field, ignore_permissions=True + recipient.receiver_by_role, field_on_user, ignore_permissions=True ) return list(set(receiver_list)) From 138d016f342eb4b1aee6c4eec1c13f434c2f3c56 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 12 Jul 2024 11:58:51 +0200 Subject: [PATCH 073/176] test: add one more test case --- .../core/doctype/communication/test_communication.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/communication/test_communication.py b/frappe/core/doctype/communication/test_communication.py index 40af4053ad..1f0b2f1519 100644 --- a/frappe/core/doctype/communication/test_communication.py +++ b/frappe/core/doctype/communication/test_communication.py @@ -222,11 +222,19 @@ class TestCommunication(FrappeTestCase): to = "Jon Doe " cc = """=?UTF-8?Q?Max_Mu=C3=9F?= , erp+Customer=Plus%2BCompany@example.org, - erp+Customer+Space%20Company@example.org""" + erp+Customer+Space%20Company@example.org, + erp+Customer+Space+Company+Plus+Encoded@example.org""" bcc = "" results = list(parse_email([to, cc, bcc])) - self.assertEqual([("Customer", "Plus+Company"), ("Customer", "Space Company")], results) + self.assertEqual( + [ + ("Customer", "Plus+Company"), + ("Customer", "Space Company"), + ("Customer", "Space Company Plus Encoded"), + ], + results, + ) results = list(parse_email([to, bcc])) self.assertEqual(results, []) From ac4104ae0b1b184fb13648c8f7ed2e2491074300 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:07:24 +0200 Subject: [PATCH 074/176] Revert "fix: use currency number format if present" (#27087) --- frappe/public/js/frappe/utils/number_format.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/public/js/frappe/utils/number_format.js b/frappe/public/js/frappe/utils/number_format.js index d5cef586f7..e0e8f00366 100644 --- a/frappe/public/js/frappe/utils/number_format.js +++ b/frappe/public/js/frappe/utils/number_format.js @@ -178,7 +178,6 @@ function get_currency_symbol(currency) { function get_number_format(currency) { return ( - (currency && frappe.model.get_value(":Currency", currency, "number_format")) || (frappe.boot && frappe.boot.sysdefaults && frappe.boot.sysdefaults.number_format) || "#,###.##" ); From f2f91d30677bf81598481f91c8de3fc0de1a927d Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 12 Jul 2024 20:11:21 +0530 Subject: [PATCH 075/176] fix: sync translations from crowdin (#27082) --- frappe/locale/sv.po | 212 ++++++++++++++++++++++++++++---------------- 1 file changed, 135 insertions(+), 77 deletions(-) diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po index 95d8b912b9..97ae089772 100644 --- a/frappe/locale/sv.po +++ b/frappe/locale/sv.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-06-30 09:33+0000\n" -"PO-Revision-Date: 2024-07-07 15:47\n" +"POT-Creation-Date: 2024-07-07 09:33+0000\n" +"PO-Revision-Date: 2024-07-11 16:55\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Swedish\n" "MIME-Version: 1.0\n" @@ -1182,8 +1182,8 @@ msgid "Add Child" msgstr "Lägg till Underval" #: public/js/frappe/views/kanban/kanban_board.html:4 -#: public/js/frappe/views/reports/query_report.js:1696 -#: public/js/frappe/views/reports/query_report.js:1699 +#: public/js/frappe/views/reports/query_report.js:1681 +#: public/js/frappe/views/reports/query_report.js:1684 #: public/js/frappe/views/reports/report_view.js:324 #: public/js/frappe/views/reports/report_view.js:349 msgid "Add Column" @@ -3899,6 +3899,7 @@ msgstr "Kalender Namn" #. Name of a DocType #: desk/doctype/calendar_view/calendar_view.json +#: public/js/frappe/list/base_list.js:208 msgid "Calendar View" msgstr "Kalender Vy" @@ -4075,7 +4076,7 @@ msgstr "Kan inte Hämta Värden" msgid "Cannot Remove" msgstr "Kan inte Ta Bort" -#: model/base_document.py:1072 +#: model/base_document.py:1073 msgid "Cannot Update After Submit" msgstr "Kan inte Uppdatera efter Godkännande" @@ -4163,7 +4164,7 @@ msgstr "Kan inte ta bort system skapad fält {0}. Dölj det ist msgid "Cannot delete {0}" msgstr "Kan inte radera {0}" -#: utils/nestedset.py:296 +#: utils/nestedset.py:299 msgid "Cannot delete {0} as it has child nodes" msgstr "Kan inte radera {0} eftersom det har underordnade noder" @@ -4171,7 +4172,7 @@ msgstr "Kan inte radera {0} eftersom det har underordnade noder" msgid "Cannot edit Standard Dashboards" msgstr "Kan inte redigera standard översikt panel" -#: email/doctype/notification/notification.py:121 +#: email/doctype/notification/notification.py:122 msgid "Cannot edit Standard Notification. To edit, please disable this and duplicate it" msgstr "Kan inte redigera standard avisering. Kopiera och skapa ny" @@ -4240,7 +4241,7 @@ msgstr "Kan inte ta bort ID fält" msgid "Cannot set 'Report' permission if 'Only If Creator' permission is set" msgstr "Kan inte ange \"Rapport\" behörighet om behörighet \"Endast om Ägare\" är angiven" -#: email/doctype/notification/notification.py:137 +#: email/doctype/notification/notification.py:138 msgid "Cannot set Notification on Document Type {0}" msgstr "Kan inte ange Avisering för DocType {0}" @@ -4415,6 +4416,8 @@ msgstr "Diagram Inställningar" #. Label of the chart_name (Link) field in DocType 'Workspace Chart' #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/workspace_chart/workspace_chart.json +#: public/js/frappe/views/reports/query_report.js:289 +#: public/js/frappe/widgets/widget_dialog.js:137 msgid "Chart Name" msgstr "Diagram Namn" @@ -4831,7 +4834,7 @@ msgctxt "Shrink code field." msgid "Collapse" msgstr "Fäll In" -#: public/js/frappe/views/reports/query_report.js:1979 +#: public/js/frappe/views/reports/query_report.js:1964 #: public/js/frappe/views/treeview.js:121 msgid "Collapse All" msgstr "Fäll In Alla" @@ -6362,6 +6365,10 @@ msgstr "Översikt Panel Namn" msgid "Dashboard Settings" msgstr "Översikt Panel Inställningar" +#: public/js/frappe/list/base_list.js:205 +msgid "Dashboard View" +msgstr "Översikt Panel Vy" + #. Label of the tab_break_2 (Tab Break) field in DocType 'Workspace' #: desk/doctype/workspace/workspace.json msgid "Dashboards" @@ -6943,7 +6950,8 @@ msgid "Department" msgstr "Avdelning" #. Label of the dependencies (Data) field in DocType 'Workspace Link' -#: desk/doctype/workspace_link/workspace_link.json www/attribution.html:29 +#: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:318 www/attribution.html:29 msgid "Dependencies" msgstr "Beroenden " @@ -7405,6 +7413,7 @@ msgstr "Status för följande tillstånd är ändrad:
    {0}
    5, <10 or =324. For ranges, use 5:10 (for values between 5 & 10)." msgstr "För jämförelse, använd >5, <10 eller = 324. För intervall, använd 5:10 (för värden mellan 5 och 10)." @@ -10730,7 +10740,7 @@ msgstr "Från Datum" msgid "From Date Field" msgstr "Från Datum" -#: public/js/frappe/views/reports/query_report.js:1704 +#: public/js/frappe/views/reports/query_report.js:1689 msgid "From Document Type" msgstr "Från DocType" @@ -10826,6 +10836,10 @@ msgstr "GNU General Public License" msgid "Gantt" msgstr "Gantt" +#: public/js/frappe/list/base_list.js:206 +msgid "Gantt View" +msgstr "Gantt Vy" + #. Label of the gender (Link) field in DocType 'Contact' #. Name of a DocType #. Label of the gender (Data) field in DocType 'Gender' @@ -12197,6 +12211,10 @@ msgstr "Bild Höjd" msgid "Image Link" msgstr "Bild Länk" +#: public/js/frappe/list/base_list.js:209 +msgid "Image View" +msgstr "Visa Bild" + #. Label of the image_width (Float) field in DocType 'Letter Head' #. Label of the footer_image_width (Float) field in DocType 'Letter Head' #: printing/doctype/letter_head/letter_head.json @@ -12468,6 +12486,10 @@ msgstr "Inkorg" msgid "Inbox User" msgstr "Inkorg Användare" +#: public/js/frappe/list/base_list.js:210 +msgid "Inbox View" +msgstr "Inkorg Vy" + #. Label of the include_name_field (Check) field in DocType 'Form Tour' #: desk/doctype/form_tour/form_tour.json msgid "Include Name Field" @@ -12487,11 +12509,11 @@ msgstr "Inkludera Tema från Appar" msgid "Include Web View Link in Email" msgstr "Inkludera Länk till Webbvy i E-post" -#: public/js/frappe/views/reports/query_report.js:1521 +#: public/js/frappe/views/reports/query_report.js:1506 msgid "Include filters" msgstr "Inkludera Filter" -#: public/js/frappe/views/reports/query_report.js:1513 +#: public/js/frappe/views/reports/query_report.js:1498 msgid "Include indentation" msgstr "Inkludera Fördjupning" @@ -12647,7 +12669,7 @@ msgstr "Infoga \tOvan" #. Label of the insert_after (Select) field in DocType 'Custom Field' #: custom/doctype/custom_field/custom_field.json -#: public/js/frappe/views/reports/query_report.js:1744 +#: public/js/frappe/views/reports/query_report.js:1729 msgid "Insert After" msgstr "Infoga Efter" @@ -12854,7 +12876,7 @@ msgstr "Ogiltig uttryck 'beroende på' i filter {0}" msgid "Invalid \"mandatory_depends_on\" expression" msgstr "Ogiltigt uttryck för \"obligatoriskt_beror_på\"" -#: utils/nestedset.py:177 +#: utils/nestedset.py:178 msgid "Invalid Action" msgstr "Ogiltig åtgärd" @@ -13225,6 +13247,7 @@ msgstr "Är Publicerad Fält måste vara giltig Fält Namn" #. Label of the is_query_report (Check) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:336 msgid "Is Query Report" msgstr "Är Dataförfråga Rapport" @@ -13328,7 +13351,7 @@ msgstr "Artikel Titel" msgid "Item Type" msgstr "Artikel Typ" -#: utils/nestedset.py:228 +#: utils/nestedset.py:229 msgid "Item cannot be added to its own descendants" msgstr "Artikel kan inte läggas till egna undertyper" @@ -13453,6 +13476,7 @@ msgstr "Anslag Tavla" #. Label of the kanban_board (Link) field in DocType 'Workspace Shortcut' #: desk/doctype/kanban_board/kanban_board.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:509 msgid "Kanban Board" msgstr "Anslag Tavla" @@ -13472,6 +13496,10 @@ msgctxt "Button in kanban view menu" msgid "Kanban Settings" msgstr "Anslag Tavla Inställningar" +#: public/js/frappe/list/base_list.js:207 +msgid "Kanban View" +msgstr "Anslag Tavla Vy" + #. Description of a DocType #: core/doctype/activity_log/activity_log.json msgid "Keep track of all update feeds" @@ -13717,7 +13745,10 @@ msgstr "LDAP Inställningar felaktiga. validering svar var: {0}" #: desk/doctype/workspace_quick_list/workspace_quick_list.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: printing/page/print_format_builder/print_format_builder.js:474 +#: public/js/frappe/widgets/widget_dialog.js:187 #: public/js/frappe/widgets/widget_dialog.js:255 +#: public/js/frappe/widgets/widget_dialog.js:304 +#: public/js/frappe/widgets/widget_dialog.js:421 #: public/js/frappe/widgets/widget_dialog.js:645 #: public/js/frappe/widgets/widget_dialog.js:678 #: templates/form_grid/fields.html:37 @@ -14284,6 +14315,8 @@ msgstr "Länk Titel" #. Label of the link_to (Dynamic Link) field in DocType 'Workspace Shortcut' #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json +#: public/js/frappe/widgets/widget_dialog.js:285 +#: public/js/frappe/widgets/widget_dialog.js:430 msgid "Link To" msgstr "Länk Till" @@ -14293,6 +14326,7 @@ msgstr "Länk Till i Rad" #. Label of the link_type (Select) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:277 msgid "Link Type" msgstr "Länk Typ" @@ -14336,7 +14370,7 @@ msgstr "Länkad Med" #. Label of the links (Table) field in DocType 'Customize Form' #. Label of the links (Table) field in DocType 'Workspace' #: contacts/doctype/address/address.js:39 contacts/doctype/address/address.json -#: contacts/doctype/contact/contact.js:87 contacts/doctype/contact/contact.json +#: contacts/doctype/contact/contact.js:92 contacts/doctype/contact/contact.json #: core/doctype/doctype/doctype.json #: custom/doctype/customize_form/customize_form.json #: desk/doctype/workspace/workspace.json public/js/frappe/form/toolbar.js:377 @@ -14389,6 +14423,10 @@ msgctxt "Button in list view menu" msgid "List Settings" msgstr "Lista Inställningar" +#: public/js/frappe/list/base_list.js:203 +msgid "List View" +msgstr "List Vy" + #. Name of a DocType #: desk/doctype/list_view_settings/list_view_settings.json msgid "List View Settings" @@ -14425,7 +14463,7 @@ msgstr "Listor" msgid "Load Balancing" msgstr "Last Balansering" -#: public/js/frappe/list/base_list.js:378 +#: public/js/frappe/list/base_list.js:386 #: website/doctype/blog_post/templates/blog_post_list.html:50 #: website/doctype/help_article/templates/help_article_list.html:30 msgid "Load More" @@ -14439,7 +14477,7 @@ msgstr "Ladda Mer Korenspondens" #: core/page/permission_manager/permission_manager.js:165 #: public/js/frappe/form/controls/multicheck.js:13 #: public/js/frappe/form/linked_with.js:13 -#: public/js/frappe/list/base_list.js:490 +#: public/js/frappe/list/base_list.js:498 #: public/js/frappe/list/list_view.js:335 public/js/frappe/ui/listing.html:16 #: public/js/frappe/views/reports/query_report.js:1017 msgid "Loading" @@ -14467,7 +14505,7 @@ msgstr "Laddar versioner..." #: public/js/frappe/views/kanban/kanban_board.html:11 #: public/js/frappe/widgets/chart_widget.js:50 #: public/js/frappe/widgets/number_card_widget.js:174 -#: public/js/frappe/widgets/quick_list_widget.js:126 +#: public/js/frappe/widgets/quick_list_widget.js:128 msgid "Loading..." msgstr "Laddar..." @@ -14852,6 +14890,10 @@ msgstr "Mapp" msgid "Map Columns" msgstr "Mappa Kolumner" +#: public/js/frappe/list/base_list.js:212 +msgid "Map View" +msgstr "Mapp Vy" + #: public/js/frappe/data_import/import_preview.js:290 msgid "Map columns from {0} to fields in {1}" msgstr "Mappa Kolumner från {0} till fält i {1}" @@ -15081,7 +15123,7 @@ msgstr "Meny" msgid "Merge with existing" msgstr "Slå samman med befintlig" -#: utils/nestedset.py:304 +#: utils/nestedset.py:307 msgid "Merging is only possible between Group-to-Group or Leaf Node-to-Leaf Node" msgstr "Sammanslafning är endast möjlig mellan grupp till grupp eller underordnad till underordnad" @@ -15237,6 +15279,10 @@ msgstr "Meta Titel för SEO" msgid "Method" msgstr "Sätt" +#: __init__.py:936 +msgid "Method Not Allowed" +msgstr "Metod ej Tillåten" + #: desk/doctype/number_card/number_card.py:70 msgid "Method is required to create a number card" msgstr "Sätt erfodras för att skapa nummerkort" @@ -15628,7 +15674,7 @@ msgstr "Flytta till nästa steg när du klickar i det markerade området." msgid "Mozilla doesn't support :has() so you can pass parent selector here as workaround" msgstr "Mozilla stöder inte :has() så du kan skicka överordnad väljare här som lösning" -#: utils/nestedset.py:328 +#: utils/nestedset.py:331 msgid "Multiple root nodes not allowed." msgstr "Flera rot noder är inte tillåtna." @@ -15866,7 +15912,7 @@ msgstr "Arbetsyta Ansvarig roll erfodras för att dölja/visa publika arbetsyto msgid "Negative Value" msgstr "Negativ Värde" -#: utils/nestedset.py:93 +#: utils/nestedset.py:94 msgid "Nested set error. Please contact the Administrator." msgstr "Nested set fel. Kontakta Administratör." @@ -16213,7 +16259,7 @@ msgstr "Nästa på Klick" #: public/js/form_builder/utils.js:341 #: public/js/frappe/form/controls/link.js:475 #: public/js/frappe/list/list_sidebar_group_by.js:223 -#: public/js/frappe/views/reports/query_report.js:1541 +#: public/js/frappe/views/reports/query_report.js:1526 #: website/doctype/help_article/templates/help_article.html:26 msgid "No" msgstr "Nej" @@ -16257,7 +16303,7 @@ msgstr "Ingen Data" msgid "No Data to Show" msgstr "Ingen Data att visa" -#: public/js/frappe/widgets/quick_list_widget.js:131 +#: public/js/frappe/widgets/quick_list_widget.js:133 msgid "No Data..." msgstr "Ingen Data..." @@ -16724,7 +16770,7 @@ msgstr "Inte Aktiv" msgid "Not allowed for {0}: {1}" msgstr "Ej tillåtet för {0}: {1}" -#: email/doctype/notification/notification.py:391 +#: email/doctype/notification/notification.py:392 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "Ej Tillåtet att bifoga {0} dokument, aktivera \"Tillåt Utskrift\" för {0} i Utskrift Inställningar" @@ -16843,7 +16889,7 @@ msgstr "Inget mer att göra om" msgid "Nothing left to undo" msgstr "Inget mer att ångra" -#: public/js/frappe/list/base_list.js:362 +#: public/js/frappe/list/base_list.js:370 #: public/js/frappe/views/reports/query_report.js:105 #: templates/includes/list/list.html:7 #: website/doctype/blog_post/templates/blog_post_list.html:41 @@ -17249,9 +17295,14 @@ msgstr "{0}, {1} skrev" #. Label of the onboard (Check) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:330 msgid "Onboard" msgstr "Introduktion" +#: public/js/frappe/widgets/widget_dialog.js:236 +msgid "Onboarding Name" +msgstr "Introduktion Namn" + #. Name of a DocType #: desk/doctype/onboarding_permission/onboarding_permission.json msgid "Onboarding Permission" @@ -17359,6 +17410,7 @@ msgstr "Endast utkast dokument kan förkastas" #. Label of the only_for (Link) field in DocType 'Workspace Link' #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/widgets/widget_dialog.js:323 msgid "Only for" msgstr "Endast för" @@ -17708,7 +17760,7 @@ msgstr "PATCH" #: printing/page/print/print.js:71 #: public/js/frappe/form/templates/print_layout.html:44 -#: public/js/frappe/views/reports/query_report.js:1669 +#: public/js/frappe/views/reports/query_report.js:1654 msgid "PDF" msgstr "PDF" @@ -18100,8 +18152,8 @@ msgid "Password not found for {0} {1} {2}" msgstr "Lösenord hittades inte för {0} {1} {2}" #: core/doctype/user/user.py:1021 -msgid "Password reset instructions have been sent to your email" -msgstr "Lösenord Återställning instruktioner har skickats till din E-post" +msgid "Password reset instructions have been sent to {}'s email" +msgstr "Instruktioner för återställning av lösenord är skickade till {}'s e-post" #: www/update-password.html:164 msgid "Password set" @@ -18500,7 +18552,7 @@ msgstr "Kontrollera OpenID Configuration URL" msgid "Please check the filter values set for Dashboard Chart: {}" msgstr "Kontrollera filter värden angivna för Översikt Panel Diagram: {}" -#: model/base_document.py:872 +#: model/base_document.py:873 msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "Kontrollera värde för uppsättning 'Hämta från' för fält {0}" @@ -18802,11 +18854,11 @@ msgstr "Specificera" msgid "Please specify a valid parent DocType for {0}" msgstr "Ange giltig överordnad DocType för {0}" -#: email/doctype/notification/notification.py:87 +#: email/doctype/notification/notification.py:88 msgid "Please specify which date field must be checked" msgstr "Ange Datum Fält som måste kontrolleras" -#: email/doctype/notification/notification.py:90 +#: email/doctype/notification/notification.py:91 msgid "Please specify which value field must be checked" msgstr "Ange Värde Fält som måste kontrolleras" @@ -19139,7 +19191,7 @@ msgstr "Primär nyckel för doctype {0} kan inte ändras eftersom det finns befi #: public/js/frappe/form/templates/print_layout.html:46 #: public/js/frappe/form/toolbar.js:332 public/js/frappe/form/toolbar.js:344 #: public/js/frappe/list/bulk_operations.js:87 -#: public/js/frappe/views/reports/query_report.js:1655 +#: public/js/frappe/views/reports/query_report.js:1640 #: public/js/frappe/views/reports/report_view.js:1460 #: public/js/frappe/views/treeview.js:469 www/printview.html:18 msgid "Print" @@ -20001,7 +20053,7 @@ msgstr "Uppdatera" msgid "Rebuild Tree" msgstr "Uppdatera Träd Vy" -#: utils/nestedset.py:176 +#: utils/nestedset.py:177 msgid "Rebuilding of tree is not supported for {}" msgstr "Uppdatering av Träd Vy stöds inte för {}" @@ -20359,7 +20411,7 @@ msgstr "Referens" #: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1196 #: public/js/frappe/form/templates/print_layout.html:6 #: public/js/frappe/list/base_list.js:66 -#: public/js/frappe/views/reports/query_report.js:1644 +#: public/js/frappe/views/reports/query_report.js:1629 #: public/js/frappe/views/treeview.js:475 #: public/js/frappe/widgets/chart_widget.js:290 #: public/js/frappe/widgets/number_card_widget.js:324 @@ -20457,7 +20509,7 @@ msgstr "Ladda om" msgid "Reload File" msgstr "Ladda om Fil" -#: public/js/frappe/list/base_list.js:242 +#: public/js/frappe/list/base_list.js:250 msgid "Reload List" msgstr "Ladda om Lista" @@ -20726,7 +20778,7 @@ msgstr "Rapport Ansvarig" #: core/doctype/report/report.json #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/number_card/number_card.json -#: public/js/frappe/views/reports/query_report.js:1825 +#: public/js/frappe/views/reports/query_report.js:1810 msgid "Report Name" msgstr "Rapport Namn" @@ -20749,6 +20801,10 @@ msgstr "Rapportera Referens DocType" msgid "Report Type" msgstr "Rapport Typ" +#: public/js/frappe/list/base_list.js:204 +msgid "Report View" +msgstr "Rapport Vy" + #: core/doctype/doctype/doctype.py:1780 msgid "Report cannot be set for Single types" msgstr "Rapport kan inte anges för Enskilda Typer" @@ -20783,7 +20839,7 @@ msgstr "Rapport är uppdaterad" msgid "Report was not saved (there were errors)" msgstr "Rapport är inte sparad (det fanns fel)" -#: public/js/frappe/views/reports/query_report.js:1863 +#: public/js/frappe/views/reports/query_report.js:1848 msgid "Report with more than 10 columns looks better in Landscape mode." msgstr "Rapport med mer än 10 kolumner ser bättre ut i Liggande Läge." @@ -21369,7 +21425,7 @@ msgstr "Roller HTML" msgid "Roles can be set for users from their User page." msgstr "Roller kan anges för användare från deras Användarsida." -#: utils/nestedset.py:277 +#: utils/nestedset.py:280 msgid "Root {0} cannot be deleted" msgstr "Root {0} kan inte raderas" @@ -21442,7 +21498,7 @@ msgstr "Rad #" msgid "Row # {0}: Non administrator user can not set the role {1} to the custom doctype" msgstr "Rad # {0}: Användare som inte är administratör kan inte ange roll {1} till anpassad Dokument Typ" -#: model/base_document.py:903 +#: model/base_document.py:904 msgid "Row #{0}:" msgstr "Rad # {0}:" @@ -21726,11 +21782,11 @@ msgstr "Lördag" #: public/js/frappe/views/kanban/kanban_settings.js:45 #: public/js/frappe/views/kanban/kanban_settings.js:189 #: public/js/frappe/views/kanban/kanban_view.js:343 -#: public/js/frappe/views/reports/query_report.js:1817 +#: public/js/frappe/views/reports/query_report.js:1802 #: public/js/frappe/views/reports/report_view.js:1640 #: public/js/frappe/views/workspace/workspace.js:501 #: public/js/frappe/widgets/base_widget.js:142 -#: public/js/frappe/widgets/quick_list_widget.js:117 +#: public/js/frappe/widgets/quick_list_widget.js:119 #: public/js/print_format_builder/print_format_builder.bundle.js:15 #: public/js/workflow_builder/workflow_builder.bundle.js:33 msgid "Save" @@ -21757,7 +21813,7 @@ msgstr "Spara Anpassningar" msgid "Save Filter" msgstr "Spara Filter " -#: public/js/frappe/views/reports/query_report.js:1820 +#: public/js/frappe/views/reports/query_report.js:1805 msgid "Save Report" msgstr "Spara Rapport" @@ -22881,7 +22937,7 @@ msgid "Set Filters" msgstr "Ange Filter" #: public/js/frappe/widgets/chart_widget.js:395 -#: public/js/frappe/widgets/quick_list_widget.js:102 +#: public/js/frappe/widgets/quick_list_widget.js:104 msgid "Set Filters for {0}" msgstr "Ange Filter för {0}" @@ -23118,7 +23174,7 @@ msgstr "Inställningar > Användar Behörigheter" msgid "Setup Approval Workflows" msgstr "Ange Arbetsflöde för Godkännande " -#: public/js/frappe/views/reports/query_report.js:1690 +#: public/js/frappe/views/reports/query_report.js:1675 #: public/js/frappe/views/reports/report_view.js:1618 msgid "Setup Auto Email" msgstr "Automatisk E-post Rapport" @@ -25154,7 +25210,7 @@ msgid "The Client ID obtained from the Google Cloud Console under " msgstr "Klient ID som erhållits från Google Cloud Console under \"API och tjänster\" > \"Inloggningsuppgifter\"" -#: email/doctype/notification/notification.py:130 +#: email/doctype/notification/notification.py:131 msgid "The Condition '{0}' is invalid" msgstr "Villkor '{0}' är ogiltig" @@ -25613,7 +25669,7 @@ msgstr "Detta format används om land specifika format inte hittas" msgid "This goes above the slideshow." msgstr "Text ovanför Bildspel." -#: public/js/frappe/views/reports/query_report.js:2027 +#: public/js/frappe/views/reports/query_report.js:2012 msgid "This is a background report. Please set the appropriate filters and then generate a new one." msgstr "Detta är bakgrund rapport. Ange lämplig filter och skapa ny rapport." @@ -26478,6 +26534,10 @@ msgstr "Skräp" msgid "Tree" msgstr "Träd Vy" +#: public/js/frappe/list/base_list.js:211 +msgid "Tree View" +msgstr "Träd Vy" + #. Description of the 'Is Tree' (Check) field in DocType 'DocType' #: core/doctype/doctype/doctype.json msgid "Tree structures are implemented using Nested Set" @@ -26583,6 +26643,7 @@ msgstr "Två Faktor Autentisering Sätt" #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: public/js/frappe/views/file/file_view.js:337 +#: public/js/frappe/widgets/widget_dialog.js:399 #: social/doctype/energy_point_log/energy_point_log.json #: website/doctype/web_template/web_template.json www/attribution.html:35 msgid "Type" @@ -26665,6 +26726,7 @@ msgstr "URI för att ta emot behörighet kod när Användare tillåter tillgång #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: integrations/doctype/integration_request/integration_request.json #: integrations/doctype/webhook_request_log/webhook_request_log.json +#: public/js/frappe/widgets/widget_dialog.js:469 #: website/doctype/top_bar_item/top_bar_item.json #: website/doctype/website_slideshow_item/website_slideshow_item.json msgid "URL" @@ -27341,7 +27403,7 @@ msgid "User Permission" msgstr "Användare Behörighet" #: core/page/permission_manager/permission_manager_help.html:30 -#: public/js/frappe/views/reports/query_report.js:1804 +#: public/js/frappe/views/reports/query_report.js:1789 #: public/js/frappe/views/reports/report_view.js:1666 msgid "User Permissions" msgstr "Användare Behörigheter" @@ -27659,7 +27721,7 @@ msgstr "Värde Ändrad" msgid "Value To Be Set" msgstr "Värde som ska Anges" -#: model/base_document.py:965 model/document.py:682 +#: model/base_document.py:966 model/document.py:682 msgid "Value cannot be changed for {0}" msgstr "Värde kan inte ändras för {0}" @@ -27702,7 +27764,7 @@ msgstr "Värde måste vara ett av {0}" msgid "Value to Validate" msgstr "Värde att Validera" -#: model/base_document.py:1035 +#: model/base_document.py:1036 msgid "Value too big" msgstr "Värde för hög" @@ -27801,7 +27863,7 @@ msgid "View Full Log" msgstr "Visa Full Logg" #: public/js/frappe/views/treeview.js:463 -#: public/js/frappe/widgets/quick_list_widget.js:245 +#: public/js/frappe/widgets/quick_list_widget.js:247 msgid "View List" msgstr "Visa Lista" @@ -28683,7 +28745,7 @@ msgstr "Slutför" msgid "Write" msgstr "Skriva" -#: model/base_document.py:875 +#: model/base_document.py:876 msgid "Wrong Fetch From value" msgstr "Fel Hämtning Från Värde" @@ -28770,7 +28832,7 @@ msgstr "Gul" #: public/js/form_builder/utils.js:336 #: public/js/frappe/form/controls/link.js:475 #: public/js/frappe/list/list_sidebar_group_by.js:223 -#: public/js/frappe/views/reports/query_report.js:1541 +#: public/js/frappe/views/reports/query_report.js:1526 #: website/doctype/help_article/templates/help_article.html:25 msgid "Yes" msgstr "Ja" @@ -29983,7 +30045,7 @@ msgstr "via Data Import" msgid "via Google Meet" msgstr "via Google Meet" -#: email/doctype/notification/notification.py:215 +#: email/doctype/notification/notification.py:216 msgid "via Notification" msgstr "via Avisering" @@ -30126,7 +30188,7 @@ msgstr "{0} Moduler" msgid "{0} Name" msgstr "{0} Namn" -#: model/base_document.py:1065 +#: model/base_document.py:1066 msgid "{0} Not allowed to change {1} after submission from {2} to {3}" msgstr "{0} Ej Tillåtet att ändra {1} efter godkännande från {2} till {3}" @@ -30152,10 +30214,6 @@ msgstr "{0} Inställningar" msgid "{0} Tree" msgstr "{0} Träd Vy" -#: public/js/frappe/list/base_list.js:209 -msgid "{0} View" -msgstr "{0} Vy" - #: public/js/frappe/form/footer/form_timeline.js:126 #: public/js/frappe/form/sidebar/form_sidebar.js:86 msgid "{0} Web page views" @@ -30770,11 +30828,11 @@ msgstr "{0} {1} är lagd till i Översikt Panel {2}" msgid "{0} {1} already exists" msgstr "{0} {1} finns redan" -#: model/base_document.py:908 +#: model/base_document.py:909 msgid "{0} {1} cannot be \"{2}\". It should be one of \"{3}\"" msgstr "{0} {1} kan inte vara \"{2}\". Det kan vara en av följande: \"{3}\"" -#: utils/nestedset.py:337 +#: utils/nestedset.py:340 msgid "{0} {1} cannot be a leaf node as it has children" msgstr "{0} {1} kan inte vara undernod då den har undernoder" @@ -30794,11 +30852,11 @@ msgstr "{0} {1} hittades inte" msgid "{0} {1}: Submitted Record cannot be deleted. You must {2} Cancel {3} it first." msgstr "{0} {1}: Godkänd Post kan inte raderas. Du måste {2} Annullera {3} det först." -#: model/base_document.py:1026 +#: model/base_document.py:1027 msgid "{0}, Row {1}" msgstr "{0}, Rad {1}" -#: model/base_document.py:1031 +#: model/base_document.py:1032 msgid "{0}: '{1}' ({3}) will get truncated, as max characters allowed is {2}" msgstr "{0}: {1} ({3}) kommer att förminskas då maximum tillåtna antal tecken är {2}" @@ -30891,7 +30949,7 @@ msgid "{0}: fieldname cannot be set to reserved keyword {1}" msgstr "{0}: fältnamn kan inte anges för reserverad sökord {1}" #: contacts/doctype/address/address.js:35 -#: contacts/doctype/contact/contact.js:83 +#: contacts/doctype/contact/contact.js:88 #: public/js/frappe/views/workspace/workspace.js:170 msgid "{0}: {1}" msgstr "{0}: {1}" From cde3d0dfdaaa4e6b32d5775e853953778cdc8f72 Mon Sep 17 00:00:00 2001 From: marination Date: Fri, 12 Jul 2024 18:28:08 +0200 Subject: [PATCH 076/176] feat: Allow Setting email, share and print perms via User Type - misc: Also hide email button if user does not have email perm on doctype (the btn in the menu is already taken care of) --- .../user_document_type.json | 36 +++++++++++++++++-- .../user_document_type/user_document_type.py | 3 ++ .../core/doctype/user_type/test_user_type.py | 12 +++++++ frappe/core/doctype/user_type/user_type.py | 5 +-- .../js/frappe/form/footer/form_timeline.js | 14 ++++---- 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/frappe/core/doctype/user_document_type/user_document_type.json b/frappe/core/doctype/user_document_type/user_document_type.json index e4e40f7548..9cca917a60 100644 --- a/frappe/core/doctype/user_document_type/user_document_type.json +++ b/frappe/core/doctype/user_document_type/user_document_type.json @@ -16,7 +16,12 @@ "submit", "cancel", "amend", - "delete" + "delete", + "additional_permissions_section", + "email", + "column_break_fjuk", + "share", + "print" ], "fields": [ { @@ -92,12 +97,39 @@ "fieldname": "delete", "fieldtype": "Check", "label": "Delete" + }, + { + "fieldname": "additional_permissions_section", + "fieldtype": "Section Break", + "label": "Additional Permissions" + }, + { + "default": "1", + "fieldname": "email", + "fieldtype": "Check", + "label": "Email" + }, + { + "fieldname": "column_break_fjuk", + "fieldtype": "Column Break" + }, + { + "default": "1", + "fieldname": "share", + "fieldtype": "Check", + "label": "Share" + }, + { + "default": "1", + "fieldname": "print", + "fieldtype": "Check", + "label": "Print" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-03-23 16:04:00.313525", + "modified": "2024-07-12 17:32:15.721862", "modified_by": "Administrator", "module": "Core", "name": "User Document Type", diff --git a/frappe/core/doctype/user_document_type/user_document_type.py b/frappe/core/doctype/user_document_type/user_document_type.py index a2b519b8ca..7641342744 100644 --- a/frappe/core/doctype/user_document_type/user_document_type.py +++ b/frappe/core/doctype/user_document_type/user_document_type.py @@ -19,11 +19,14 @@ class UserDocumentType(Document): create: DF.Check delete: DF.Check document_type: DF.Link + email: DF.Check is_custom: DF.Check parent: DF.Data parentfield: DF.Data parenttype: DF.Data + print: DF.Check read: DF.Check + share: DF.Check submit: DF.Check write: DF.Check # end: auto-generated types diff --git a/frappe/core/doctype/user_type/test_user_type.py b/frappe/core/doctype/user_type/test_user_type.py index ec1a5e3bfc..08ba0ceaab 100644 --- a/frappe/core/doctype/user_type/test_user_type.py +++ b/frappe/core/doctype/user_type/test_user_type.py @@ -31,6 +31,18 @@ class TestUserType(FrappeTestCase): for entry in link_fields: self.assertTrue(entry.options in select_doctypes) + def test_print_share_email_default(self): + """Test if print, share & email values default to 1. (for backward compatibility)""" + # create user type with read, write permissions + create_user_type("Test User Type") + + # check if print, share & email values are set to 1 + perm = frappe.get_all("Custom DocPerm", filters={"role": "_Test User Type"}, fields=["*"])[0] + + self.assertTrue(perm.print == 1) + self.assertTrue(perm.share == 1) + self.assertTrue(perm.email == 1) + def tearDown(self): frappe.db.rollback() diff --git a/frappe/core/doctype/user_type/user_type.py b/frappe/core/doctype/user_type/user_type.py index 7478b71782..09440b8abc 100644 --- a/frappe/core/doctype/user_type/user_type.py +++ b/frappe/core/doctype/user_type/user_type.py @@ -137,13 +137,10 @@ class UserType(Document): user.set("block_modules", block_modules) def add_role_permissions_for_user_doctypes(self): - perms = ["read", "write", "create", "submit", "cancel", "amend", "delete"] + perms = ["read", "write", "create", "submit", "cancel", "amend", "delete", "print", "email", "share"] for row in self.user_doctypes: docperm = add_role_permissions(row.document_type, self.role) - values = {perm: row.get(perm, default=0) for perm in perms} - for perm in ["print", "email", "share"]: - values[perm] = 1 frappe.db.set_value("Custom DocPerm", docperm, values) diff --git a/frappe/public/js/frappe/form/footer/form_timeline.js b/frappe/public/js/frappe/form/footer/form_timeline.js index 2d27fe12c3..c79c17619f 100644 --- a/frappe/public/js/frappe/form/footer/form_timeline.js +++ b/frappe/public/js/frappe/form/footer/form_timeline.js @@ -22,12 +22,14 @@ class FormTimeline extends BaseTimeline { } setup_timeline_actions() { - this.add_action_button( - __("New Email"), - () => this.compose_mail(), - "es-line-add", - "btn-secondary" - ); + if (frappe.model.can_email(null, this.frm)) { + this.add_action_button( + __("New Email"), + () => this.compose_mail(), + "es-line-add", + "btn-secondary" + ); + } this.setup_new_event_button(); } From 55e71031e6a82627483488f7466612859c32840b Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Fri, 12 Jul 2024 19:18:11 +0200 Subject: [PATCH 077/176] chore: bump boto3 to 1.34.143 (#27094) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 79c4d519b9..6b27020480 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dependencies = [ "markdownify~=0.11.6", # integration dependencies - "boto3~=1.28.10", + "boto3~=1.34.143", "dropbox~=11.36.2", "google-api-python-client~=2.2.0", "google-auth-oauthlib~=0.4.4", From aae0cd896ec30484a33a5c5709df86a76e9b1f59 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 12 Jul 2024 19:54:10 +0200 Subject: [PATCH 078/176] refactor: frappe.cache.set_value redis.set accepts ex kwarg, etc --- frappe/utils/redis_wrapper.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/frappe/utils/redis_wrapper.py b/frappe/utils/redis_wrapper.py index c38f54a2f2..e494d07bab 100644 --- a/frappe/utils/redis_wrapper.py +++ b/frappe/utils/redis_wrapper.py @@ -2,6 +2,7 @@ # License: MIT. See LICENSE import pickle import re +from contextlib import suppress import redis from redis.commands.search import Search @@ -62,14 +63,8 @@ class RedisWrapper(redis.Redis): if not expires_in_sec: frappe.local.cache[key] = val - try: - if expires_in_sec: - self.setex(name=key, time=expires_in_sec, value=pickle.dumps(val)) - else: - self.set(key, pickle.dumps(val)) - - except redis.exceptions.ConnectionError: - return None + with suppress(redis.exceptions.ConnectionError): + self.set(name=key, value=pickle.dumps(val), ex=expires_in_sec) def get_value(self, key, generator=None, user=None, expires=False, shared=False): """Return cache value. If not found and generator function is From 281e04bd5e10759541e6e10b8a4966d1c7e618e1 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 12 Jul 2024 20:08:18 +0200 Subject: [PATCH 079/176] fix: Enqueue Notification log creation after commit Avoid ghost notifications in case the transaction gets rolled back --- frappe/desk/doctype/notification_log/notification_log.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py index 70f31606c1..8793559611 100644 --- a/frappe/desk/doctype/notification_log/notification_log.py +++ b/frappe/desk/doctype/notification_log/notification_log.py @@ -93,6 +93,7 @@ def enqueue_create_notification(users: list[str] | str, doc: dict): doc=doc, users=users, now=frappe.flags.in_test, + enqueue_after_commit=not frappe.flags.in_test, ) From aee278b6aec4f19e20af8c0da3ebd54f9f1edbac Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 12 Jul 2024 20:10:30 +0200 Subject: [PATCH 080/176] fix: Pass string method path to q.enqueue_call Passing a method results in rq doing some internal gymnastics to generate this string. In our case, this function never changes so we can get rid of those steps --- frappe/utils/background_jobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index 815145ef70..4e2a7c71b9 100644 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -163,7 +163,7 @@ def enqueue( def enqueue_call(): return q.enqueue_call( - execute_job, + "frappe.utils.background_jobs.execute_job", on_success=Callback(func=on_success) if on_success else None, on_failure=Callback(func=on_failure) if on_failure else None, timeout=timeout, From 3930f3b5fa4759700313e27ca7ca657ea7417dfb Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Sat, 13 Jul 2024 10:40:40 +0530 Subject: [PATCH 081/176] fix: precommit check --- frappe/public/js/frappe/widgets/chart_widget.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index db7553cc43..cfaba04a71 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -141,7 +141,8 @@ export default class ChartWidget extends Widget { } else { filters = [ { - label: __(this.chart_settings.time_interval) || __(this.chart_doc.time_interval), + label: + __(this.chart_settings.time_interval) || __(this.chart_doc.time_interval), options: ["Yearly", "Quarterly", "Monthly", "Weekly", "Daily"], icon: "calendar", class: "time-interval-filter", @@ -473,7 +474,9 @@ export default class ChartWidget extends Widget { ${actions .map( (action) => - `
  • ${__(action.label)}
  • ` + `
  • ${__( + action.label + )}
  • ` ) .join("")} From 6fde29ff17e67febae4a68ef9434249248a6f98d Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Sat, 13 Jul 2024 10:42:08 +0530 Subject: [PATCH 082/176] fix: pre commit check --- frappe/public/js/frappe/widgets/onboarding_widget.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/widgets/onboarding_widget.js b/frappe/public/js/frappe/widgets/onboarding_widget.js index bddb040df2..ae4b86d8a4 100644 --- a/frappe/public/js/frappe/widgets/onboarding_widget.js +++ b/frappe/public/js/frappe/widgets/onboarding_widget.js @@ -129,8 +129,8 @@ export default class OnboardingWidget extends Widget { .on("click", toggle_video); } else { $( - `` ) .appendTo(this.step_footer) @@ -168,9 +168,9 @@ export default class OnboardingWidget extends Widget { }); $( - `` + `` ) .appendTo(this.step_footer) .on("click", () => { From 413c6d9301c0028de215eab141392c246e6cd785 Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Sat, 13 Jul 2024 10:46:19 +0530 Subject: [PATCH 083/176] fix: precommit check --- frappe/public/js/frappe/form/form_tour.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form_tour.js b/frappe/public/js/frappe/form/form_tour.js index 82933350de..61f9ec07e2 100644 --- a/frappe/public/js/frappe/form/form_tour.js +++ b/frappe/public/js/frappe/form/form_tour.js @@ -137,7 +137,11 @@ frappe.ui.form.FormTour = class FormTour { return { element, name, - popover: { title: __(title), description: __(description), position: frappe.router.slug(position || "Bottom") }, + popover: { + title: __(title), + description: __(description), + position: frappe.router.slug(position || "Bottom"), + }, onNext: on_next, onPrevious: on_prev, }; From 95eb6c4b0930b3dd4f3f7f919fb1c68e7c0b9329 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Sat, 13 Jul 2024 07:26:48 +0200 Subject: [PATCH 084/176] fix: translation in messages.js (#26911) --- frappe/public/js/frappe/ui/messages.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/ui/messages.js b/frappe/public/js/frappe/ui/messages.js index 999fcc5125..4850ccb7a5 100644 --- a/frappe/public/js/frappe/ui/messages.js +++ b/frappe/public/js/frappe/ui/messages.js @@ -228,7 +228,7 @@ frappe.msgprint = function (msg, title, is_minimizable) { } frappe.msg_dialog.set_primary_action( - __(data.primary_action.label || data.primary_action_label || "Done"), + __(data.primary_action.label) || __(data.primary_action_label) || __("Done"), data.primary_action.action ); } else { @@ -240,7 +240,9 @@ frappe.msgprint = function (msg, title, is_minimizable) { if (data.secondary_action) { frappe.msg_dialog.set_secondary_action(data.secondary_action.action); - frappe.msg_dialog.set_secondary_action_label(__(data.secondary_action.label || "Close")); + frappe.msg_dialog.set_secondary_action_label( + __(data.secondary_action.label) || __("Close") + ); } if (data.message == null) { From de4c275e662283ec74b7cdda9fa9a95d72cbb986 Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Sat, 13 Jul 2024 11:30:34 +0530 Subject: [PATCH 085/176] fix: doc name cannot be translated --- frappe/desk/form/load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 459904eb7d..7409941b60 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -38,7 +38,7 @@ def getdoc(doctype, name, user=None): if not doc.has_permission("read"): frappe.flags.error_message = _("Insufficient Permission for {0}").format( - frappe.bold(_(doctype) + " " + _(name)) + frappe.bold(_(doctype) + " " + name) ) raise frappe.PermissionError(("read", doctype, name)) From 1861302edf08b9fbf98ceea1543f846bab5cd886 Mon Sep 17 00:00:00 2001 From: asharkinasuit Date: Sat, 13 Jul 2024 14:01:38 +0800 Subject: [PATCH 086/176] fix(list view): check field list filter could only be set once, then shows Loading... --- frappe/public/js/frappe/list/base_list.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index feb60154cb..890c89ef0d 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -455,12 +455,9 @@ frappe.views.BaseList = class BaseList { get_filter_value(fieldname) { const filter = this.get_filters_for_args().filter((f) => f[1] == fieldname)[0]; if (!filter) return; - return ( - { - like: filter[3]?.replace(/^%?|%$/g, ""), - "not set": null, - }[filter[2]] || filter[3] - ); + if (filter[2] === "like") return filter[3]?.replace(/^%?|%$/g, ""); + else if (filter[2] === "not set") return null; + else return filter[3]; } get_filters_for_args() { From 7e2da2be6ca32a75cfd7aa486aa4467d84c6bef3 Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Sat, 13 Jul 2024 11:39:16 +0530 Subject: [PATCH 087/176] fix: precommit check --- frappe/core/page/permission_manager/permission_manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/page/permission_manager/permission_manager.js b/frappe/core/page/permission_manager/permission_manager.js index 8fd6f59f38..0df30519e9 100644 --- a/frappe/core/page/permission_manager/permission_manager.js +++ b/frappe/core/page/permission_manager/permission_manager.js @@ -122,7 +122,7 @@ frappe.PermissionEngine = class PermissionEngine { // show standard permissions let $d = $(d.wrapper) .find(".frappe-confirm-message") - .append("
    ${__("Standard Permissions")}:

    "); + .append(`
    ${__("Standard Permissions")}:

    `); let $wrapper = $("

    ").appendTo($d); data.message.forEach((d) => { let rights = this.rights From ad46d2886189289d50bece87a92d79c34b2ba987 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Sat, 13 Jul 2024 22:46:26 +0530 Subject: [PATCH 088/176] fix: Swedish translations --- frappe/locale/sv.po | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po index 97ae089772..0e9ee42c93 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: 2024-07-07 09:33+0000\n" -"PO-Revision-Date: 2024-07-11 16:55\n" +"PO-Revision-Date: 2024-07-13 17:16\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Swedish\n" "MIME-Version: 1.0\n" @@ -540,7 +540,7 @@ msgstr "

    E-post Svar Exempel

    \n\n" "- Kund: {{ customer }}\n" "- Belopp: {{ grand_total }}\n" "\n\n" -"

    Hur man får fältnamn

    \n\n" +"

    Hur hämtas fältnamn

    \n\n" "

    Fältnamn som kan använda i e-post mall är fält i dokument som du skickar e-post meddelande från. Ta reda på fält namn för alla dokument via Inställningar > Anpassa formulär vy och välja dokument typ (t.ex. Försäljning Faktura)

    \n\n" "

    Mallar

    \n\n" "

    Mallar kompileras med Jinja Templating Language. För att lära dig mer om Jinja, läs denna dokumentation.

    \n" @@ -1292,7 +1292,7 @@ msgstr "Lägg till Mall" #. Label of the add_total_row (Check) field in DocType 'Report' #: core/doctype/report/report.json msgid "Add Total Row" -msgstr "Lägg till Totalt Rad" +msgstr "Lägg till Totalt Antal Rader" #. Label of the add_unsubscribe_link (Check) field in DocType 'Email Queue' #: email/doctype/email_queue/email_queue.json @@ -3154,7 +3154,7 @@ msgstr "Bakgrund Jobb" #. Report' #: desk/doctype/system_health_report/system_health_report.json msgid "Background Jobs Check" -msgstr "Bakgrund Jobb Koll" +msgstr "Bakgrund Jobb Status" #. Label of the background_jobs_queue (Autocomplete) field in DocType 'Webhook' #: integrations/doctype/webhook/webhook.json @@ -3407,7 +3407,7 @@ msgstr "Faktura Kontakt" #. Label of the binary_logging (Data) field in DocType 'System Health Report' #: desk/doctype/system_health_report/system_health_report.json msgid "Binary Logging" -msgstr "Fakturering Logg" +msgstr "Binär Logg" #. Label of the bio (Small Text) field in DocType 'User' #. Label of the bio (Small Text) field in DocType 'About Us Team Member' @@ -13879,7 +13879,7 @@ msgstr "Senaste Tilldelning Datum" #. Option for the 'Timespan' (Select) field in DocType 'Dashboard Chart' #: desk/doctype/dashboard_chart/dashboard_chart.json msgid "Last Quarter" -msgstr "Sista Kvartal" +msgstr "Förra Kvartal" #. Label of the last_reset_password_key_generated_on (Datetime) field in #. DocType 'User' @@ -17093,7 +17093,7 @@ msgstr "Antal dagar efter vilka dokument Webb Vy länk delad i e-post kommer att #. Label of the cache_keys (Int) field in DocType 'System Health Report' #: desk/doctype/system_health_report/system_health_report.json msgid "Number of keys" -msgstr "Antal nycklar" +msgstr "Antal Nycklar" #. Label of the onsite_backups (Int) field in DocType 'System Health Report' #: desk/doctype/system_health_report/system_health_report.json @@ -17710,7 +17710,7 @@ msgstr "Utgående (SMTP) Inställningar" #. Health Report' #: desk/doctype/system_health_report/system_health_report.json msgid "Outgoing Emails (Last 7 days)" -msgstr "Utgående E-post (sista 7 dagar)" +msgstr "Utgående E-post (Senaste 7 dagar)" #. Label of the smtp_server (Data) field in DocType 'Email Account' #. Label of the smtp_server (Data) field in DocType 'Email Domain' @@ -18250,24 +18250,24 @@ msgstr "Pågående" #. Request' #: website/doctype/personal_data_deletion_request/personal_data_deletion_request.json msgid "Pending Approval" -msgstr "Pågående Godkännande" +msgstr "Godkännande Kö" #. Label of the pending_emails (Int) field in DocType 'System Health Report' #: desk/doctype/system_health_report/system_health_report.json msgid "Pending Emails" -msgstr "Pågående E-post" +msgstr "E-post Kö" #. Label of the pending_jobs (Int) field in DocType 'System Health Report #. Queue' #: desk/doctype/system_health_report_queue/system_health_report_queue.json msgid "Pending Jobs" -msgstr "Pågående Jobb" +msgstr "Jobb Kö" #. Option for the 'Status' (Select) field in DocType 'Personal Data Deletion #. Request' #: website/doctype/personal_data_deletion_request/personal_data_deletion_request.json msgid "Pending Verification" -msgstr "Pågående Verifiering" +msgstr "Verifiering Kö" #. Option for the 'Type' (Select) field in DocType 'DocField' #. Option for the 'Field Type' (Select) field in DocType 'Custom Field' @@ -26340,16 +26340,16 @@ msgstr "Totalt" #. Report' #: desk/doctype/system_health_report/system_health_report.json msgid "Total Background Workers" -msgstr "Totalt Bakgrund Tjänster" +msgstr "Totalt Antal Bakgrund Tjänster" #. Label of the total_errors (Int) field in DocType 'System Health Report' #: desk/doctype/system_health_report/system_health_report.json msgid "Total Errors (last 1 day)" -msgstr "Totalt Fel (sista dagen)" +msgstr "Totalt Antal Fel (Senaste dag)" #: public/js/frappe/ui/capture.js:259 msgid "Total Images" -msgstr "Totalt Bilder" +msgstr "Totalt Antal Bilder" #. Label of the total_outgoing_emails (Int) field in DocType 'System Health #. Report' @@ -26378,18 +26378,18 @@ msgstr "Totalt Användare" #. Label of the total_views (Int) field in DocType 'Newsletter' #: email/doctype/newsletter/newsletter.json msgid "Total Views" -msgstr "Totalt Visningar" +msgstr "Totalt Antal Visningar" #. Label of the total_working_time (Duration) field in DocType 'RQ Worker' #: core/doctype/rq_worker/rq_worker.json msgid "Total Working Time" -msgstr "Totalt Antal Arbetstimmar" +msgstr "Totalt Antal Arbetade Timmar" #. Description of the 'Initial Sync Count' (Select) field in DocType 'Email #. Account' #: email/doctype/email_account/email_account.json msgid "Total number of emails to sync in initial sync process " -msgstr "Totalt antal E-post meddelande som ska synkroniseras i första synkronisering behandling" +msgstr "Totalt antal E-post meddelande som ska synkroniseras i första synkronisering " #: public/js/frappe/views/reports/report_view.js:1178 msgid "Totals" @@ -26397,7 +26397,7 @@ msgstr "Totals" #: public/js/frappe/views/reports/report_view.js:1153 msgid "Totals Row" -msgstr "Totalt Rad" +msgstr "Totalt Antal Rader" #. Label of the trace_id (Data) field in DocType 'Error Log' #: core/doctype/error_log/error_log.json From c5886a81f31dd944b960464096b9f1e87a0a3e73 Mon Sep 17 00:00:00 2001 From: frappe-pr-bot Date: Sun, 14 Jul 2024 09:33:19 +0000 Subject: [PATCH 089/176] chore: update POT file --- frappe/locale/main.pot | 464 ++++++++++++++++++++++++----------------- 1 file changed, 267 insertions(+), 197 deletions(-) diff --git a/frappe/locale/main.pot b/frappe/locale/main.pot index 4606279c89..a9fbc81610 100644 --- a/frappe/locale/main.pot +++ b/frappe/locale/main.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Frappe Framework VERSION\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-07-07 09:33+0000\n" -"PO-Revision-Date: 2024-07-07 09:33+0000\n" +"POT-Creation-Date: 2024-07-14 09:33+0000\n" +"PO-Revision-Date: 2024-07-14 09:33+0000\n" "Last-Translator: developers@frappe.io\n" "Language-Team: developers@frappe.io\n" "MIME-Version: 1.0\n" @@ -96,7 +96,7 @@ msgstr "" msgid "'{0}' not allowed for type {1} in row {2}" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:301 +#: public/js/frappe/data_import/data_exporter.js:302 msgid "(Mandatory)" msgstr "" @@ -167,7 +167,7 @@ msgstr "" msgid "1 month ago" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:226 +#: public/js/frappe/data_import/data_exporter.js:227 msgid "1 record will be exported" msgstr "" @@ -692,10 +692,11 @@ msgid "API Endpoint Args" msgstr "" #. Label of the api_key (Data) field in DocType 'User' +#. Label of the api_key (Data) field in DocType 'Email Account' #. Label of the api_key (Data) field in DocType 'Google Settings' #. Label of the sb_01 (Section Break) field in DocType 'Google Settings' #. Label of the api_key (Data) field in DocType 'Push Notification Settings' -#: core/doctype/user/user.json +#: core/doctype/user/user.json email/doctype/email_account/email_account.json #: integrations/doctype/google_settings/google_settings.json #: integrations/doctype/push_notification_settings/push_notification_settings.json msgid "API Key" @@ -718,9 +719,10 @@ msgid "API Method" msgstr "" #. Label of the api_secret (Password) field in DocType 'User' +#. Label of the api_secret (Password) field in DocType 'Email Account' #. Label of the api_secret (Password) field in DocType 'Push Notification #. Settings' -#: core/doctype/user/user.json +#: core/doctype/user/user.json email/doctype/email_account/email_account.json #: integrations/doctype/push_notification_settings/push_notification_settings.json msgid "API Secret" msgstr "" @@ -985,11 +987,6 @@ msgstr "" msgid "Add" msgstr "" -#: public/js/frappe/list/list_view.js:266 -msgctxt "Primary action in list view" -msgid "Add" -msgstr "" - #: public/js/frappe/form/grid_row.js:431 msgid "Add / Remove Columns" msgstr "" @@ -1027,6 +1024,10 @@ msgstr "" msgid "Add Border at Top" msgstr "" +#: desk/doctype/number_card/number_card.js:36 +msgid "Add Card to Dashboard" +msgstr "" + #: public/js/frappe/views/reports/query_report.js:210 msgid "Add Chart to Dashboard" msgstr "" @@ -1101,7 +1102,7 @@ msgstr "" msgid "Add Review" msgstr "" -#: core/doctype/user/user.py:757 +#: core/doctype/user/user.py:765 msgid "Add Roles" msgstr "" @@ -1134,7 +1135,7 @@ msgstr "" msgid "Add Tags" msgstr "" -#: public/js/frappe/list/list_view.js:1903 +#: public/js/frappe/list/list_view.js:1955 msgctxt "Button in list view actions menu" msgid "Add Tags" msgstr "" @@ -1170,7 +1171,7 @@ msgstr "" msgid "Add a New Role" msgstr "" -#: public/js/frappe/form/form_tour.js:205 +#: public/js/frappe/form/form_tour.js:211 msgid "Add a Row" msgstr "" @@ -1228,6 +1229,11 @@ msgstr "" msgid "Add {0}" msgstr "" +#: public/js/frappe/list/list_view.js:264 +msgctxt "Primary action in list view" +msgid "Add {0}" +msgstr "" + #. Description of the '<head> HTML' (Code) field in DocType 'Website #. Settings' #: website/doctype/website_settings/website_settings.json @@ -1347,11 +1353,11 @@ msgstr "" msgid "Administrator" msgstr "" -#: core/doctype/user/user.py:1161 +#: core/doctype/user/user.py:1169 msgid "Administrator Logged In" msgstr "" -#: core/doctype/user/user.py:1155 +#: core/doctype/user/user.py:1163 msgid "Administrator accessed {0} on {1} via IP Address {2}." msgstr "" @@ -1829,7 +1835,7 @@ msgstr "" msgid "Allowing DocType, DocType. Be careful!" msgstr "" -#: core/doctype/user/user.py:964 +#: core/doctype/user/user.py:972 msgid "Already Registered" msgstr "" @@ -2045,7 +2051,7 @@ msgstr "" msgid "App not found for module: {0}" msgstr "" -#: __init__.py:1794 +#: __init__.py:1800 msgid "App {0} is not installed" msgstr "" @@ -2065,7 +2071,7 @@ msgstr "" msgid "Append To" msgstr "" -#: email/doctype/email_account/email_account.py:185 +#: email/doctype/email_account/email_account.py:195 msgid "Append To can be one of {0}" msgstr "" @@ -2106,7 +2112,7 @@ msgstr "" msgid "Applied On" msgstr "" -#: public/js/frappe/list/list_view.js:1888 +#: public/js/frappe/list/list_view.js:1940 msgctxt "Button in list view actions menu" msgid "Apply Assignment Rule" msgstr "" @@ -2200,7 +2206,7 @@ msgstr "" msgid "Archived Columns" msgstr "" -#: public/js/frappe/list/list_view.js:1867 +#: public/js/frappe/list/list_view.js:1919 msgid "Are you sure you want to clear the assignments?" msgstr "" @@ -2296,7 +2302,7 @@ msgstr "" msgid "Assign To" msgstr "" -#: public/js/frappe/list/list_view.js:1849 +#: public/js/frappe/list/list_view.js:1901 msgctxt "Button in list view actions menu" msgid "Assign To" msgstr "" @@ -2603,7 +2609,15 @@ msgstr "" msgid "Authentication Apps you can use are: " msgstr "" -#: email/doctype/email_account/email_account.py:312 +#: email/frappemail.py:89 +msgid "Authentication Error: Invalid API Key or Secret" +msgstr "" + +#: email/frappemail.py:85 +msgid "Authentication Error: Reauthorize OAuth for Email Account {0}." +msgstr "" + +#: email/doctype/email_account/email_account.py:328 msgid "Authentication failed while receiving emails from Email Account: {0}." msgstr "" @@ -2817,11 +2831,11 @@ msgstr "" msgid "Automatic" msgstr "" -#: email/doctype/email_account/email_account.py:715 +#: email/doctype/email_account/email_account.py:761 msgid "Automatic Linking can be activated only for one Email Account." msgstr "" -#: email/doctype/email_account/email_account.py:709 +#: email/doctype/email_account/email_account.py:755 msgid "Automatic Linking can be activated only if Incoming is enabled." msgstr "" @@ -3860,7 +3874,7 @@ msgstr "" msgid "Cancel" msgstr "" -#: public/js/frappe/list/list_view.js:1958 +#: public/js/frappe/list/list_view.js:2010 msgctxt "Button in list view actions menu" msgid "Cancel" msgstr "" @@ -3882,7 +3896,7 @@ msgstr "" msgid "Cancel Scheduling" msgstr "" -#: public/js/frappe/list/list_view.js:1963 +#: public/js/frappe/list/list_view.js:2015 msgctxt "Title of confirmation dialog" msgid "Cancel {0} documents?" msgstr "" @@ -3982,7 +3996,7 @@ msgstr "" msgid "Cannot delete Home and Attachments folders" msgstr "" -#: model/delete_doc.py:373 +#: model/delete_doc.py:382 msgid "Cannot delete or cancel because {0} {1} is linked with {2} {3} {4}" msgstr "" @@ -4095,8 +4109,8 @@ msgstr "" msgid "Cannot set 'Report' permission if 'Only If Creator' permission is set" msgstr "" -#: email/doctype/notification/notification.py:138 -msgid "Cannot set Notification on Document Type {0}" +#: email/doctype/notification/notification.py:139 +msgid "Cannot set Notification with event {0} on Document Type {1}" msgstr "" #: core/doctype/docshare/docshare.py:67 @@ -4445,7 +4459,7 @@ msgstr "" msgid "Clear & Add template" msgstr "" -#: public/js/frappe/list/list_view.js:1864 +#: public/js/frappe/list/list_view.js:1916 msgctxt "Button in list view actions menu" msgid "Clear Assignment" msgstr "" @@ -4544,7 +4558,7 @@ msgstr "" msgid "Click to Set Filters" msgstr "" -#: public/js/frappe/list/list_view.js:680 +#: public/js/frappe/list/list_view.js:677 msgid "Click to sort by {0}" msgstr "" @@ -4624,7 +4638,8 @@ msgid "Client URLs" msgstr "" #: core/doctype/communication/communication.js:39 desk/doctype/todo/todo.js:23 -#: public/js/frappe/ui/messages.js:243 website/js/bootstrap-4.js:24 +#: public/js/frappe/form/form_tour.js:17 public/js/frappe/ui/messages.js:244 +#: website/js/bootstrap-4.js:24 msgid "Close" msgstr "" @@ -4679,7 +4694,7 @@ msgstr "" msgid "Code challenge method" msgstr "" -#: public/js/frappe/form/form_tour.js:270 +#: public/js/frappe/form/form_tour.js:276 #: public/js/frappe/widgets/base_widget.js:159 msgid "Collapse" msgstr "" @@ -4981,7 +4996,7 @@ msgstr "" msgid "Complete By" msgstr "" -#: core/doctype/user/user.py:426 templates/emails/new_user.html:10 +#: core/doctype/user/user.py:425 templates/emails/new_user.html:10 msgid "Complete Registration" msgstr "" @@ -5546,7 +5561,7 @@ msgstr "" msgid "Create New" msgstr "" -#: public/js/frappe/list/list_view.js:487 +#: public/js/frappe/list/list_view.js:484 msgctxt "Create a new document from list view" msgid "Create New" msgstr "" @@ -5586,7 +5601,7 @@ msgstr "" #: public/js/frappe/form/controls/link.js:295 #: public/js/frappe/form/controls/link.js:297 #: public/js/frappe/form/link_selector.js:139 -#: public/js/frappe/list/list_view.js:476 +#: public/js/frappe/list/list_view.js:473 #: public/js/frappe/web_form/web_form_list.js:225 msgid "Create a new {0}" msgstr "" @@ -5613,7 +5628,7 @@ msgstr "" msgid "Create or Edit Workflow" msgstr "" -#: public/js/frappe/list/list_view.js:479 +#: public/js/frappe/list/list_view.js:476 msgid "Create your first {0}" msgstr "" @@ -5644,7 +5659,7 @@ msgid "Created Custom Field {0} in {1}" msgstr "" #: desk/doctype/dashboard_chart/dashboard_chart.js:241 -#: email/doctype/notification/notification.js:30 model/meta.py:46 +#: email/doctype/notification/notification.js:32 model/meta.py:46 #: public/js/frappe/model/meta.js:198 public/js/frappe/model/model.js:125 #: public/js/frappe/views/dashboard/dashboard_view.js:478 msgid "Created On" @@ -6014,7 +6029,7 @@ msgstr "" msgid "Customize" msgstr "" -#: public/js/frappe/list/list_view.js:1709 +#: public/js/frappe/list/list_view.js:1761 msgctxt "Button in list view menu" msgid "Customize" msgstr "" @@ -6029,6 +6044,7 @@ msgstr "" #. Name of a DocType #: automation/doctype/auto_repeat/auto_repeat.js:33 +#: core/doctype/doctype/doctype.js:65 #: custom/doctype/customize_form/customize_form.json #: public/js/frappe/views/kanban/kanban_view.js:343 msgid "Customize Form" @@ -6259,7 +6275,7 @@ msgstr "" msgid "Data" msgstr "" -#: public/js/frappe/form/controls/data.js:58 +#: public/js/frappe/form/controls/data.js:59 msgid "Data Clipped" msgstr "" @@ -6364,6 +6380,7 @@ msgstr "" #. Trail' #: core/doctype/audit_trail/audit_trail.json #: desk/page/leaderboard/leaderboard.js:165 +#: public/js/frappe/widgets/chart_widget.js:237 msgid "Date Range" msgstr "" @@ -6497,7 +6514,7 @@ msgstr "" #. Label of the default_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:201 +#: email/doctype/email_account/email_account.py:217 msgid "Default Incoming" msgstr "" @@ -6517,7 +6534,7 @@ msgstr "" #. Label of the default_outgoing (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:209 +#: email/doctype/email_account/email_account.py:225 msgid "Default Outgoing" msgstr "" @@ -6632,7 +6649,7 @@ msgstr "" msgid "Defaults" msgstr "" -#: email/doctype/email_account/email_account.py:220 +#: email/doctype/email_account/email_account.py:236 msgid "Defaults Updated" msgstr "" @@ -6668,7 +6685,7 @@ msgstr "" msgid "Delete" msgstr "" -#: public/js/frappe/list/list_view.js:1926 +#: public/js/frappe/list/list_view.js:1978 msgctxt "Button in list view actions menu" msgid "Delete" msgstr "" @@ -6705,12 +6722,12 @@ msgstr "" msgid "Delete this record to allow sending to this email address" msgstr "" -#: public/js/frappe/list/list_view.js:1931 +#: public/js/frappe/list/list_view.js:1983 msgctxt "Title of confirmation dialog" msgid "Delete {0} item permanently?" msgstr "" -#: public/js/frappe/list/list_view.js:1937 +#: public/js/frappe/list/list_view.js:1989 msgctxt "Title of confirmation dialog" msgid "Delete {0} items permanently?" msgstr "" @@ -7097,7 +7114,7 @@ msgstr "" msgid "Disabled" msgstr "" -#: email/doctype/email_account/email_account.js:232 +#: email/doctype/email_account/email_account.js:261 msgid "Disabled Auto Reply" msgstr "" @@ -7478,7 +7495,7 @@ msgstr "" #: core/doctype/user_permission/user_permission_list.js:36 #: core/doctype/version/version.json desk/doctype/tag_link/tag_link.json #: email/doctype/document_follow/document_follow.json -#: public/js/frappe/form/form_tour.js:60 +#: public/js/frappe/form/form_tour.js:62 msgid "Document Name" msgstr "" @@ -7662,15 +7679,15 @@ msgstr "" msgid "Document Unlocked" msgstr "" -#: public/js/frappe/list/list_view.js:1081 +#: public/js/frappe/list/list_view.js:1116 msgid "Document has been cancelled" msgstr "" -#: public/js/frappe/list/list_view.js:1080 +#: public/js/frappe/list/list_view.js:1115 msgid "Document has been submitted" msgstr "" -#: public/js/frappe/list/list_view.js:1079 +#: public/js/frappe/list/list_view.js:1114 msgid "Document is in draft state" msgstr "" @@ -7793,7 +7810,7 @@ msgstr "" msgid "Don't have an account?" msgstr "" -#: public/js/frappe/ui/messages.js:231 +#: public/js/frappe/form/form_tour.js:16 public/js/frappe/ui/messages.js:231 #: public/js/onboarding_tours/onboarding_tours.js:17 msgid "Done" msgstr "" @@ -8042,7 +8059,7 @@ msgstr "" #: public/js/frappe/views/workspace/workspace.js:460 #: public/js/frappe/views/workspace/workspace.js:816 #: public/js/frappe/widgets/base_widget.js:64 -#: public/js/frappe/widgets/chart_widget.js:298 +#: public/js/frappe/widgets/chart_widget.js:299 #: public/js/frappe/widgets/number_card_widget.js:331 #: templates/discussions/reply_card.html:29 #: templates/discussions/reply_section.html:29 @@ -8051,7 +8068,7 @@ msgstr "" msgid "Edit" msgstr "" -#: public/js/frappe/list/list_view.js:2012 +#: public/js/frappe/list/list_view.js:2064 msgctxt "Button in list view actions menu" msgid "Edit" msgstr "" @@ -8081,7 +8098,7 @@ msgstr "" msgid "Edit DocType" msgstr "" -#: public/js/frappe/list/list_view.js:1736 +#: public/js/frappe/list/list_view.js:1788 msgctxt "Button in list view menu" msgid "Edit DocType" msgstr "" @@ -8274,7 +8291,7 @@ msgctxt "Email Account" msgid "Email Account" msgstr "" -#: email/doctype/email_account/email_account.py:316 +#: email/doctype/email_account/email_account.py:332 msgid "Email Account Disabled." msgstr "" @@ -8283,7 +8300,7 @@ msgstr "" msgid "Email Account Name" msgstr "" -#: core/doctype/user/user.py:690 +#: core/doctype/user/user.py:698 msgid "Email Account added multiple times" msgstr "" @@ -8579,7 +8596,7 @@ msgstr "" #. Label of the enable_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:202 +#: email/doctype/email_account/email_account.py:218 msgid "Enable Incoming" msgstr "" @@ -8592,7 +8609,7 @@ msgstr "" #. Label of the enable_outgoing (Check) field in DocType 'Email Account' #: core/doctype/user_email/user_email.json #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:210 +#: email/doctype/email_account/email_account.py:226 msgid "Enable Outgoing" msgstr "" @@ -8733,7 +8750,7 @@ msgstr "" msgid "Enabled Scheduler" msgstr "" -#: email/doctype/email_account/email_account.py:936 +#: email/doctype/email_account/email_account.py:982 msgid "Enabled email inbox for user {0}" msgstr "" @@ -8746,7 +8763,7 @@ msgstr "" msgid "Enables Calendar and Gantt views." msgstr "" -#: email/doctype/email_account/email_account.js:227 +#: email/doctype/email_account/email_account.js:256 msgid "Enabling auto reply on an incoming email account will send automated replies to all the synchronized emails. Do you wish to continue?" msgstr "" @@ -8854,6 +8871,8 @@ msgstr "" #. 'Notification Settings' #: desk/doctype/notification_settings/notification_settings.json #: desk/page/user_profile/user_profile.html:28 +#: desk/page/user_profile/user_profile_controller.js:80 +#: desk/page/user_profile/user_profile_controller.js:114 #: desk/page/user_profile/user_profile_controller.js:402 #: templates/emails/energy_points_summary.html:39 msgid "Energy Points" @@ -8894,7 +8913,7 @@ msgctxt "Title of prompt dialog" msgid "Enter Value" msgstr "" -#: public/js/frappe/form/form_tour.js:58 +#: public/js/frappe/form/form_tour.js:60 msgid "Enter a name for this {0}" msgstr "" @@ -8925,7 +8944,7 @@ msgstr "" msgid "Enter url parameter for receiver nos" msgstr "" -#: public/js/frappe/ui/messages.js:332 +#: public/js/frappe/ui/messages.js:334 msgid "Enter your password" msgstr "" @@ -9016,9 +9035,9 @@ msgstr "" msgid "Error in Header/Footer Script" msgstr "" -#: email/doctype/notification/notification.py:395 -#: email/doctype/notification/notification.py:511 -#: email/doctype/notification/notification.py:517 +#: email/doctype/notification/notification.py:399 +#: email/doctype/notification/notification.py:515 +#: email/doctype/notification/notification.py:521 msgid "Error in Notification" msgstr "" @@ -9026,11 +9045,11 @@ msgstr "" msgid "Error in print format on line {0}: {1}" msgstr "" -#: email/doctype/email_account/email_account.py:614 +#: email/doctype/email_account/email_account.py:659 msgid "Error while connecting to email account {0}" msgstr "" -#: email/doctype/notification/notification.py:508 +#: email/doctype/notification/notification.py:512 msgid "Error while evaluating Notification {0}. Please fix your template." msgstr "" @@ -9261,19 +9280,19 @@ msgstr "" #. Label of the export (Check) field in DocType 'DocPerm' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json core/doctype/recorder/recorder_list.js:37 -#: public/js/frappe/data_import/data_exporter.js:91 -#: public/js/frappe/data_import/data_exporter.js:242 +#: public/js/frappe/data_import/data_exporter.js:92 +#: public/js/frappe/data_import/data_exporter.js:243 #: public/js/frappe/views/reports/query_report.js:1669 #: public/js/frappe/views/reports/report_view.js:1550 msgid "Export" msgstr "" -#: public/js/frappe/list/list_view.js:2034 +#: public/js/frappe/list/list_view.js:2086 msgctxt "Button in list view actions menu" msgid "Export" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:244 +#: public/js/frappe/data_import/data_exporter.js:245 msgid "Export 1 record" msgstr "" @@ -9346,7 +9365,7 @@ msgstr "" msgid "Export without main header" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:246 +#: public/js/frappe/data_import/data_exporter.js:247 msgid "Export {0} records" msgstr "" @@ -9499,7 +9518,7 @@ msgstr "" msgid "Failed to optimize image: {0}" msgstr "" -#: email/doctype/email_queue/email_queue.py:281 +#: email/doctype/email_queue/email_queue.py:294 msgid "Failed to send email with subject:" msgstr "" @@ -10358,6 +10377,10 @@ msgstr "" msgid "For example if you cancel and amend INV004 it will become a new document INV004-1. This helps you to keep track of each amendment." msgstr "" +#: public/js/frappe/utils/dashboard_utils.js:162 +msgid "For example:" +msgstr "" + #: printing/page/print_format_builder/print_format_builder.js:744 msgid "For example: If you want to include the document ID, use {0}" msgstr "" @@ -10537,6 +10560,20 @@ msgstr "" msgid "Frappe Light" msgstr "" +#. Option for the 'Service' (Select) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json email/frappemail.py:91 +msgid "Frappe Mail" +msgstr "" + +#: email/doctype/email_account/email_account.py:538 +msgid "Frappe Mail OAuth Error" +msgstr "" + +#. Label of the frappe_mail_site (Data) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json +msgid "Frappe Mail Site" +msgstr "" + #. Label of a standard help item #. Type: Action #: hooks.py @@ -10654,7 +10691,7 @@ msgstr "" msgid "Function Based On" msgstr "" -#: __init__.py:934 +#: __init__.py:940 msgid "Function {0} is not whitelisted." msgstr "" @@ -10741,7 +10778,7 @@ msgstr "" msgid "Geolocation" msgstr "" -#: email/doctype/notification/notification.js:170 +#: email/doctype/notification/notification.js:175 msgid "Get Alerts for Today" msgstr "" @@ -11566,7 +11603,7 @@ msgstr "" msgid "Hide Standard Menu" msgstr "" -#: public/js/frappe/list/list_view.js:1611 +#: public/js/frappe/list/list_view.js:1663 msgid "Hide Tags" msgstr "" @@ -11687,11 +11724,11 @@ msgstr "" #: core/doctype/data_import/importer.py:1139 #: core/doctype/data_import/importer.py:1204 #: core/doctype/data_import/importer.py:1207 desk/report/todo/todo.py:36 -#: model/meta.py:45 public/js/frappe/data_import/data_exporter.js:329 -#: public/js/frappe/data_import/data_exporter.js:344 +#: model/meta.py:45 public/js/frappe/data_import/data_exporter.js:330 +#: public/js/frappe/data_import/data_exporter.js:345 #: public/js/frappe/list/list_settings.js:334 -#: public/js/frappe/list/list_view.js:358 -#: public/js/frappe/list/list_view.js:422 public/js/frappe/model/meta.js:197 +#: public/js/frappe/list/list_view.js:355 +#: public/js/frappe/list/list_view.js:419 public/js/frappe/model/meta.js:197 #: public/js/frappe/model/model.js:122 msgid "ID" msgstr "" @@ -12131,7 +12168,7 @@ msgstr "" msgid "Import" msgstr "" -#: public/js/frappe/list/list_view.js:1673 +#: public/js/frappe/list/list_view.js:1725 msgctxt "Button in list view menu" msgid "Import" msgstr "" @@ -12380,7 +12417,7 @@ msgstr "" #. Label of the incoming_popimap_tab (Tab Break) field in DocType 'Email #. Account' #: email/doctype/email_account/email_account.json -msgid "Incoming (POP/IMAP)" +msgid "Incoming" msgstr "" #. Label of the mailbox_settings (Section Break) field in DocType 'Email @@ -12824,7 +12861,7 @@ msgstr "" msgid "Invalid Parameters." msgstr "" -#: core/doctype/user/user.py:1176 www/update-password.html:121 +#: core/doctype/user/user.py:1184 www/update-password.html:121 #: www/update-password.html:142 www/update-password.html:144 #: www/update-password.html:245 msgid "Invalid Password" @@ -13700,7 +13737,7 @@ msgstr "" msgid "Last Login" msgstr "" -#: email/doctype/notification/notification.js:31 +#: email/doctype/notification/notification.js:33 msgid "Last Modified Date" msgstr "" @@ -13748,6 +13785,11 @@ msgstr "" msgid "Last Sync On" msgstr "" +#. Label of the last_synced_at (Datetime) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json +msgid "Last Synced At" +msgstr "" + #. Label of the last_synced_on (Datetime) field in DocType 'Dashboard Chart' #: desk/doctype/dashboard_chart/dashboard_chart.json msgid "Last Synced On" @@ -13778,7 +13820,7 @@ msgstr "" msgid "Last Year" msgstr "" -#: public/js/frappe/widgets/chart_widget.js:698 +#: public/js/frappe/widgets/chart_widget.js:701 msgid "Last synced {0}" msgstr "" @@ -13830,7 +13872,7 @@ msgid "Leave blank to repeat always" msgstr "" #: core/doctype/communication/mixins.py:207 -#: email/doctype/email_account/email_account.py:663 +#: email/doctype/email_account/email_account.py:709 msgid "Leave this conversation" msgstr "" @@ -13889,7 +13931,7 @@ msgstr "" msgid "Length of {0} should be between 1 and 1000" msgstr "" -#: public/js/frappe/widgets/chart_widget.js:674 +#: public/js/frappe/widgets/chart_widget.js:677 msgid "Less" msgstr "" @@ -13972,6 +14014,7 @@ msgstr "" #. Label of the level (Select) field in DocType 'Help Article' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json +#: core/page/permission_manager/permission_manager.js:137 #: core/page/permission_manager/permission_manager.js:213 #: public/js/frappe/roles_editor.js:66 #: website/doctype/help_article/help_article.json @@ -14274,7 +14317,7 @@ msgstr "" msgid "List Settings" msgstr "" -#: public/js/frappe/list/list_view.js:1753 +#: public/js/frappe/list/list_view.js:1805 msgctxt "Button in list view menu" msgid "List Settings" msgstr "" @@ -14334,7 +14377,7 @@ msgstr "" #: public/js/frappe/form/controls/multicheck.js:13 #: public/js/frappe/form/linked_with.js:13 #: public/js/frappe/list/base_list.js:498 -#: public/js/frappe/list/list_view.js:335 public/js/frappe/ui/listing.html:16 +#: public/js/frappe/list/list_view.js:332 public/js/frappe/ui/listing.html:16 #: public/js/frappe/views/reports/query_report.js:1017 msgid "Loading" msgstr "" @@ -14445,7 +14488,7 @@ msgstr "" msgid "Login Failed please try again" msgstr "" -#: email/doctype/email_account/email_account.py:141 +#: email/doctype/email_account/email_account.py:140 msgid "Login Id is required" msgstr "" @@ -15016,7 +15059,7 @@ msgstr "" msgid "Message" msgstr "" -#: __init__.py:618 public/js/frappe/ui/messages.js:265 +#: __init__.py:624 public/js/frappe/ui/messages.js:267 msgctxt "Default title of the message dialog" msgid "Message" msgstr "" @@ -15057,7 +15100,7 @@ msgstr "" msgid "Message clipped" msgstr "" -#: email/doctype/email_account/email_account.py:317 +#: email/doctype/email_account/email_account.py:333 msgid "Message from server: {0}" msgstr "" @@ -15136,7 +15179,7 @@ msgstr "" msgid "Method" msgstr "" -#: __init__.py:936 +#: __init__.py:942 msgid "Method Not Allowed" msgstr "" @@ -15449,7 +15492,7 @@ msgstr "" #: public/js/frappe/form/multi_select_dialog.js:72 #: public/js/frappe/ui/toolbar/search.js:285 #: public/js/frappe/ui/toolbar/search.js:300 -#: public/js/frappe/widgets/chart_widget.js:674 +#: public/js/frappe/widgets/chart_widget.js:677 #: templates/includes/list/list.html:23 #: templates/includes/search_template.html:13 msgid "More" @@ -15735,12 +15778,12 @@ msgstr "" msgid "Navigate Home" msgstr "" -#: public/js/frappe/list/list_view.js:1161 +#: public/js/frappe/list/list_view.js:1196 msgctxt "Description of a list view shortcut" msgid "Navigate list down" msgstr "" -#: public/js/frappe/list/list_view.js:1168 +#: public/js/frappe/list/list_view.js:1203 msgctxt "Description of a list view shortcut" msgid "Navigate list up" msgstr "" @@ -15977,7 +16020,7 @@ msgstr "" msgid "New {} releases for the following apps are available" msgstr "" -#: core/doctype/user/user.py:753 +#: core/doctype/user/user.py:761 msgid "Newly created user {0} has no roles enabled." msgstr "" @@ -16028,7 +16071,7 @@ msgstr "" msgid "Newsletters" msgstr "" -#: public/js/frappe/form/form_tour.js:318 +#: public/js/frappe/form/form_tour.js:14 public/js/frappe/form/form_tour.js:324 #: public/js/frappe/web_form/web_form.js:91 #: public/js/onboarding_tours/onboarding_tours.js:15 #: public/js/onboarding_tours/onboarding_tours.js:240 @@ -16178,7 +16221,7 @@ msgstr "" msgid "No Entry for the User {0} found within LDAP!" msgstr "" -#: public/js/frappe/widgets/chart_widget.js:366 +#: public/js/frappe/widgets/chart_widget.js:367 msgid "No Filters Set" msgstr "" @@ -16256,7 +16299,7 @@ msgstr "" msgid "No Results found" msgstr "" -#: core/doctype/user/user.py:754 +#: core/doctype/user/user.py:762 msgid "No Roles Specified" msgstr "" @@ -16284,7 +16327,7 @@ msgstr "" msgid "No address added yet." msgstr "" -#: email/doctype/notification/notification.js:180 +#: email/doctype/notification/notification.js:185 msgid "No alerts for today" msgstr "" @@ -16411,7 +16454,7 @@ msgstr "" msgid "No of Sent SMS" msgstr "" -#: __init__.py:1126 client.py:109 client.py:151 +#: __init__.py:1132 client.py:109 client.py:151 msgid "No permission for {0}" msgstr "" @@ -16440,7 +16483,7 @@ msgstr "" msgid "No records tagged." msgstr "" -#: public/js/frappe/data_import/data_exporter.js:224 +#: public/js/frappe/data_import/data_exporter.js:225 msgid "No records will be exported" msgstr "" @@ -16464,7 +16507,7 @@ msgstr "" msgid "No {0} found" msgstr "" -#: public/js/frappe/list/list_view.js:469 +#: public/js/frappe/list/list_view.js:466 msgid "No {0} found with matching filters. Clear filters to see all {0}." msgstr "" @@ -16506,7 +16549,7 @@ msgstr "" msgid "Normalized Query" msgstr "" -#: core/doctype/user/user.py:959 templates/includes/login/login.js:257 +#: core/doctype/user/user.py:967 templates/includes/login/login.js:257 #: utils/oauth.py:265 msgid "Not Allowed" msgstr "" @@ -16553,7 +16596,7 @@ msgstr "" msgid "Not Nullable" msgstr "" -#: __init__.py:1018 app.py:357 desk/calendar.py:26 geo/utils.py:97 +#: __init__.py:1024 app.py:357 desk/calendar.py:26 geo/utils.py:97 #: public/js/frappe/web_form/webform_script.js:15 #: website/doctype/web_form/web_form.py:602 #: website/page_renderers/not_permitted_page.py:20 www/login.py:181 @@ -16605,7 +16648,7 @@ msgstr "" msgid "Not a valid Comma Separated Value (CSV File)" msgstr "" -#: core/doctype/user/user.py:235 +#: core/doctype/user/user.py:234 msgid "Not a valid User Image." msgstr "" @@ -16625,7 +16668,7 @@ msgstr "" msgid "Not allowed for {0}: {1}" msgstr "" -#: email/doctype/notification/notification.py:392 +#: email/doctype/notification/notification.py:396 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "" @@ -17011,7 +17054,7 @@ msgstr "" msgid "OAuth Scope" msgstr "" -#: email/doctype/email_account/email_account.js:182 +#: email/doctype/email_account/email_account.js:211 msgid "OAuth has been enabled but not authorised. Please use \"Authorise API Access\" button to do the same." msgstr "" @@ -17211,7 +17254,7 @@ msgstr "" msgid "Only 200 inserts allowed in one request" msgstr "" -#: email/doctype/email_queue/email_queue.py:81 +#: email/doctype/email_queue/email_queue.py:82 msgid "Only Administrator can delete Email Queue" msgstr "" @@ -17375,7 +17418,7 @@ msgstr "" msgid "Open a module or tool" msgstr "" -#: public/js/frappe/list/list_view.js:1214 +#: public/js/frappe/list/list_view.js:1249 msgctxt "Description of a list view shortcut" msgid "Open list item" msgstr "" @@ -17550,9 +17593,9 @@ msgstr "" msgid "Other" msgstr "" -#. Label of the outgoing_smtp_tab (Tab Break) field in DocType 'Email Account' +#. Label of the outgoing_tab (Tab Break) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -msgid "Outgoing (SMTP)" +msgid "Outgoing" msgstr "" #. Label of the outgoing_mail_settings (Section Break) field in DocType 'Email @@ -17968,11 +18011,11 @@ msgstr "" msgid "Password" msgstr "" -#: core/doctype/user/user.py:1022 +#: core/doctype/user/user.py:1030 msgid "Password Email Sent" msgstr "" -#: core/doctype/user/user.py:406 +#: core/doctype/user/user.py:405 msgid "Password Reset" msgstr "" @@ -17994,7 +18037,7 @@ msgstr "" msgid "Password for Base DN" msgstr "" -#: email/doctype/email_account/email_account.py:172 +#: email/doctype/email_account/email_account.py:182 msgid "Password is required or select Awaiting Password" msgstr "" @@ -18006,7 +18049,7 @@ msgstr "" msgid "Password not found for {0} {1} {2}" msgstr "" -#: core/doctype/user/user.py:1021 +#: core/doctype/user/user.py:1029 msgid "Password reset instructions have been sent to {}'s email" msgstr "" @@ -18018,7 +18061,7 @@ msgstr "" msgid "Password size exceeded the maximum allowed size" msgstr "" -#: core/doctype/user/user.py:817 +#: core/doctype/user/user.py:825 msgid "Password size exceeded the maximum allowed size." msgstr "" @@ -18351,6 +18394,10 @@ msgstr "" msgid "Plant" msgstr "" +#: email/doctype/email_account/email_account.py:535 +msgid "Please Authorize OAuth for Email Account {0}" +msgstr "" + #: email/oauth.py:29 msgid "Please Authorize OAuth for Email Account {}" msgstr "" @@ -18379,7 +18426,7 @@ msgstr "" msgid "Please add a valid comment." msgstr "" -#: core/doctype/user/user.py:1004 +#: core/doctype/user/user.py:1012 msgid "Please ask your administrator to verify your sign-up" msgstr "" @@ -18411,7 +18458,7 @@ msgstr "" msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "" -#: core/doctype/user/user.py:1002 +#: core/doctype/user/user.py:1010 msgid "Please check your email for verification" msgstr "" @@ -18693,11 +18740,11 @@ msgstr "" msgid "Please setup a message first" msgstr "" -#: email/doctype/email_account/email_account.py:407 +#: email/doctype/email_account/email_account.py:423 msgid "Please setup default Email Account from Settings > Email Account" msgstr "" -#: core/doctype/user/user.py:371 +#: core/doctype/user/user.py:370 msgid "Please setup default outgoing Email Account from Settings > Email Account" msgstr "" @@ -18978,6 +19025,7 @@ msgstr "" msgid "Preview:" msgstr "" +#: public/js/frappe/form/form_tour.js:15 #: public/js/frappe/web_form/web_form.js:95 #: public/js/onboarding_tours/onboarding_tours.js:16 #: templates/includes/slideshow.html:34 @@ -19052,7 +19100,7 @@ msgstr "" msgid "Print" msgstr "" -#: public/js/frappe/list/list_view.js:1918 +#: public/js/frappe/list/list_view.js:1970 msgctxt "Button in list view actions menu" msgid "Print" msgstr "" @@ -19312,7 +19360,7 @@ msgstr "" msgid "Processing" msgstr "" -#: email/doctype/email_queue/email_queue.py:434 +#: email/doctype/email_queue/email_queue.py:447 msgid "Processing..." msgstr "" @@ -19448,7 +19496,7 @@ msgstr "" msgid "Publishing Dates" msgstr "" -#: email/doctype/email_account/email_account.js:159 +#: email/doctype/email_account/email_account.js:179 msgid "Pull Emails" msgstr "" @@ -19795,7 +19843,7 @@ msgstr "" msgid "Re-Run in Console" msgstr "" -#: email/doctype/email_account/email_account.py:669 +#: email/doctype/email_account/email_account.py:715 msgid "Re:" msgstr "" @@ -20268,7 +20316,7 @@ msgstr "" #: public/js/frappe/list/base_list.js:66 #: public/js/frappe/views/reports/query_report.js:1629 #: public/js/frappe/views/treeview.js:475 -#: public/js/frappe/widgets/chart_widget.js:290 +#: public/js/frappe/widgets/chart_widget.js:291 #: public/js/frappe/widgets/number_card_widget.js:324 msgid "Refresh" msgstr "" @@ -20295,7 +20343,7 @@ msgstr "" msgid "Refresh Token" msgstr "" -#: public/js/frappe/list/list_view.js:507 +#: public/js/frappe/list/list_view.js:504 msgctxt "Document count in list view" msgid "Refreshing" msgstr "" @@ -20305,7 +20353,7 @@ msgstr "" msgid "Refreshing..." msgstr "" -#: core/doctype/user/user.py:966 +#: core/doctype/user/user.py:974 msgid "Registered but disabled" msgstr "" @@ -20848,7 +20896,7 @@ msgstr "" msgid "Reset Changes" msgstr "" -#: public/js/frappe/widgets/chart_widget.js:305 +#: public/js/frappe/widgets/chart_widget.js:306 msgid "Reset Chart" msgstr "" @@ -21196,7 +21244,7 @@ msgstr "" msgid "Role Permissions Manager" msgstr "" -#: public/js/frappe/list/list_view.js:1695 +#: public/js/frappe/list/list_view.js:1747 msgctxt "Button in list view menu" msgid "Role Permissions Manager" msgstr "" @@ -21228,7 +21276,7 @@ msgstr "" msgid "Role and Level" msgstr "" -#: core/doctype/user/user.py:316 +#: core/doctype/user/user.py:315 msgid "Role has been set as per the user type {0}" msgstr "" @@ -21529,7 +21577,7 @@ msgstr "" msgid "SMS was not sent. Please contact Administrator." msgstr "" -#: email/doctype/email_account/email_account.py:189 +#: email/doctype/email_account/email_account.py:205 msgid "SMTP Server is required" msgstr "" @@ -21681,7 +21729,7 @@ msgstr "" msgid "Save on Completion" msgstr "" -#: public/js/frappe/form/form_tour.js:289 +#: public/js/frappe/form/form_tour.js:295 msgid "Save the document." msgstr "" @@ -22083,7 +22131,7 @@ msgstr "" msgid "Select" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:148 +#: public/js/frappe/data_import/data_exporter.js:149 #: public/js/frappe/form/controls/multicheck.js:166 msgid "Select All" msgstr "" @@ -22171,11 +22219,11 @@ msgstr "" msgid "Select Fields" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:146 +#: public/js/frappe/data_import/data_exporter.js:147 msgid "Select Fields To Insert" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:147 +#: public/js/frappe/data_import/data_exporter.js:148 msgid "Select Fields To Update" msgstr "" @@ -22208,7 +22256,7 @@ msgstr "" msgid "Select List View" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:157 +#: public/js/frappe/data_import/data_exporter.js:158 msgid "Select Mandatory" msgstr "" @@ -22290,7 +22338,7 @@ msgstr "" msgid "Select a valid Subject field for creating documents from Email" msgstr "" -#: public/js/frappe/form/form_tour.js:315 +#: public/js/frappe/form/form_tour.js:321 msgid "Select an Image" msgstr "" @@ -22312,13 +22360,13 @@ msgstr "" msgid "Select atleast 2 actions" msgstr "" -#: public/js/frappe/list/list_view.js:1228 +#: public/js/frappe/list/list_view.js:1263 msgctxt "Description of a list view shortcut" msgid "Select list item" msgstr "" -#: public/js/frappe/list/list_view.js:1180 -#: public/js/frappe/list/list_view.js:1196 +#: public/js/frappe/list/list_view.js:1215 +#: public/js/frappe/list/list_view.js:1231 msgctxt "Description of a list view shortcut" msgid "Select multiple list items" msgstr "" @@ -22760,6 +22808,14 @@ msgstr "" msgid "Session Expiry must be in format {0}" msgstr "" +#: desk/doctype/dashboard_chart/dashboard_chart.js:400 +#: desk/doctype/dashboard_chart/dashboard_chart.js:487 +#: desk/doctype/number_card/number_card.js:295 +#: desk/doctype/number_card/number_card.js:387 +#: public/js/frappe/widgets/chart_widget.js:407 +msgid "Set" +msgstr "" + #: public/js/frappe/ui/filters/filter.js:569 msgctxt "Field value is set" msgid "Set" @@ -22791,7 +22847,7 @@ msgstr "" msgid "Set Filters" msgstr "" -#: public/js/frappe/widgets/chart_widget.js:395 +#: public/js/frappe/widgets/chart_widget.js:396 #: public/js/frappe/widgets/quick_list_widget.js:104 msgid "Set Filters for {0}" msgstr "" @@ -22880,6 +22936,10 @@ msgstr "" msgid "Set by user" msgstr "" +#: public/js/frappe/utils/dashboard_utils.js:162 +msgid "Set dynamic filter values in JavaScript for the required fields here." +msgstr "" + #. Description of the 'Precision' (Select) field in DocType 'DocField' #. Description of the 'Precision' (Select) field in DocType 'Custom Field' #. Description of the 'Precision' (Select) field in DocType 'Customize Form @@ -23270,7 +23330,7 @@ msgid "Show Sidebar" msgstr "" #: public/js/frappe/list/list_sidebar.html:66 -#: public/js/frappe/list/list_view.js:1611 +#: public/js/frappe/list/list_view.js:1663 msgid "Show Tags" msgstr "" @@ -23411,7 +23471,7 @@ msgstr "" msgid "Sign Up and Confirmation" msgstr "" -#: core/doctype/user/user.py:959 +#: core/doctype/user/user.py:967 msgid "Sign Up is disabled" msgstr "" @@ -23809,6 +23869,10 @@ msgstr "" msgid "Standard Not Set" msgstr "" +#: core/page/permission_manager/permission_manager.js:125 +msgid "Standard Permissions" +msgstr "" + #: printing/doctype/print_format/print_format.py:74 msgid "Standard Print Format cannot be updated" msgstr "" @@ -24211,7 +24275,7 @@ msgstr "" msgid "Submit" msgstr "" -#: public/js/frappe/list/list_view.js:1985 +#: public/js/frappe/list/list_view.js:2037 msgctxt "Button in list view actions menu" msgid "Submit" msgstr "" @@ -24268,7 +24332,7 @@ msgstr "" msgid "Submit this document to confirm" msgstr "" -#: public/js/frappe/list/list_view.js:1990 +#: public/js/frappe/list/list_view.js:2042 msgctxt "Title of confirmation dialog" msgid "Submit {0} documents?" msgstr "" @@ -24418,7 +24482,7 @@ msgstr "" msgid "Suggested Indexes" msgstr "" -#: core/doctype/user/user.py:674 +#: core/doctype/user/user.py:682 msgid "Suggested Username: {0}" msgstr "" @@ -24941,7 +25005,7 @@ msgstr "" msgid "Templates" msgstr "" -#: core/doctype/user/user.py:970 +#: core/doctype/user/user.py:978 msgid "Temporarily Disabled" msgstr "" @@ -25097,7 +25161,7 @@ msgstr "" msgid "The comment cannot be empty" msgstr "" -#: public/js/frappe/list/list_view.js:630 +#: public/js/frappe/list/list_view.js:627 msgid "The count shown is an estimated count. Click here to see the accurate count." msgstr "" @@ -25197,11 +25261,11 @@ msgid "" "" msgstr "" -#: core/doctype/user/user.py:930 +#: core/doctype/user/user.py:938 msgid "The reset password link has been expired" msgstr "" -#: core/doctype/user/user.py:932 +#: core/doctype/user/user.py:940 msgid "The reset password link has either been used before or is invalid" msgstr "" @@ -25239,7 +25303,7 @@ msgstr "" msgid "The user from this field will be rewarded points" msgstr "" -#: public/js/frappe/form/controls/data.js:24 +#: public/js/frappe/form/controls/data.js:25 msgid "The value you pasted was {0} characters long. Max allowed characters is {1}." msgstr "" @@ -25400,7 +25464,7 @@ msgstr "" msgid "This action is irreversible. Do you wish to continue?" msgstr "" -#: __init__.py:1014 +#: __init__.py:1020 msgid "This action is only allowed for {}" msgstr "" @@ -25633,7 +25697,7 @@ msgstr "" msgid "This will terminate the job immediately and might be dangerous, are you sure? " msgstr "" -#: core/doctype/user/user.py:1190 +#: core/doctype/user/user.py:1198 msgid "Throttled" msgstr "" @@ -26056,7 +26120,7 @@ msgstr "" msgid "Toggle Sidebar" msgstr "" -#: public/js/frappe/list/list_view.js:1726 +#: public/js/frappe/list/list_view.js:1778 msgctxt "Button in list view menu" msgid "Toggle Sidebar" msgstr "" @@ -26103,7 +26167,7 @@ msgstr "" msgid "Too many changes to database in single action." msgstr "" -#: core/doctype/user/user.py:971 +#: core/doctype/user/user.py:979 msgid "Too many users signed up recently, so the registration is disabled. Please try back in an hour" msgstr "" @@ -26717,7 +26781,7 @@ msgstr "" msgid "Unsafe SQL query" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:158 +#: public/js/frappe/data_import/data_exporter.js:159 #: public/js/frappe/form/controls/multicheck.js:166 msgid "Unselect All" msgstr "" @@ -26887,7 +26951,7 @@ msgctxt "Freeze message while updating a document" msgid "Updating" msgstr "" -#: email/doctype/email_queue/email_queue.py:433 +#: email/doctype/email_queue/email_queue.py:446 msgid "Updating Email Queue Statuses. The emails will be picked up in the next scheduled run." msgstr "" @@ -27245,7 +27309,7 @@ msgstr "" msgid "User Permissions" msgstr "" -#: public/js/frappe/list/list_view.js:1684 +#: public/js/frappe/list/list_view.js:1736 msgctxt "Button in list view menu" msgid "User Permissions" msgstr "" @@ -27352,7 +27416,7 @@ msgstr "" msgid "User must always select" msgstr "" -#: model/delete_doc.py:235 +#: model/delete_doc.py:244 msgid "User not allowed to delete {0}: {1}" msgstr "" @@ -27368,15 +27432,15 @@ msgstr "" msgid "User with email: {0} does not exist in the system. Please ask 'System Administrator' to create the user for you." msgstr "" -#: core/doctype/user/user.py:485 +#: core/doctype/user/user.py:484 msgid "User {0} cannot be deleted" msgstr "" -#: core/doctype/user/user.py:280 +#: core/doctype/user/user.py:279 msgid "User {0} cannot be disabled" msgstr "" -#: core/doctype/user/user.py:556 +#: core/doctype/user/user.py:564 msgid "User {0} cannot be renamed" msgstr "" @@ -27397,7 +27461,7 @@ msgstr "" msgid "User {0} has requested for data deletion" msgstr "" -#: core/doctype/user/user.py:1319 +#: core/doctype/user/user.py:1327 msgid "User {0} impersonated as {1}" msgstr "" @@ -27425,7 +27489,7 @@ msgstr "" msgid "Username" msgstr "" -#: core/doctype/user/user.py:641 +#: core/doctype/user/user.py:649 msgid "Username {0} already exists" msgstr "" @@ -27488,6 +27552,12 @@ msgstr "" msgid "Validate Field" msgstr "" +#. Label of the validate_frappe_mail_settings (Button) field in DocType 'Email +#. Account' +#: email/doctype/email_account/email_account.json +msgid "Validate Frappe Mail Settings" +msgstr "" + #. Label of the validate_ssl_certificate (Check) field in DocType 'Email #. Account' #. Label of the validate_ssl_certificate (Check) field in DocType 'Email @@ -27647,11 +27717,11 @@ msgstr "" msgid "Verified" msgstr "" -#: public/js/frappe/ui/messages.js:350 +#: public/js/frappe/ui/messages.js:352 msgid "Verify" msgstr "" -#: public/js/frappe/ui/messages.js:349 +#: public/js/frappe/ui/messages.js:351 msgid "Verify Password" msgstr "" @@ -28262,11 +28332,11 @@ msgstr "" msgid "Welcome Workspace" msgstr "" -#: core/doctype/user/user.py:363 +#: core/doctype/user/user.py:362 msgid "Welcome email sent" msgstr "" -#: core/doctype/user/user.py:424 +#: core/doctype/user/user.py:423 msgid "Welcome to {0}" msgstr "" @@ -28753,7 +28823,7 @@ msgstr "" msgid "You are not permitted to access this page." msgstr "" -#: __init__.py:933 +#: __init__.py:939 msgid "You are not permitted to access this resource." msgstr "" @@ -28765,7 +28835,7 @@ msgstr "" msgid "You are only allowed to update order, do not remove or add apps." msgstr "" -#: email/doctype/email_account/email_account.js:216 +#: email/doctype/email_account/email_account.js:245 msgid "You are selecting Sync Option as ALL, It will resync all read as well as unread message from server. This may also cause the duplication of Communication (emails)." msgstr "" @@ -28806,8 +28876,8 @@ msgstr "" msgid "You can continue with the onboarding after exploring this page" msgstr "" -#: core/doctype/user/user.py:543 -msgid "You can disable the user instead of deleting it." +#: model/delete_doc.py:136 +msgid "You can disable this {0} instead of deleting it." msgstr "" #: core/doctype/file/file.py:691 @@ -29007,7 +29077,7 @@ msgstr "" msgid "You haven't added any Dashboard Charts or Number Cards yet." msgstr "" -#: public/js/frappe/list/list_view.js:473 +#: public/js/frappe/list/list_view.js:470 msgid "You haven't created a {0} yet" msgstr "" @@ -29076,7 +29146,7 @@ msgstr "" msgid "You need to select indexes you want to add first." msgstr "" -#: email/doctype/email_account/email_account.py:147 +#: email/doctype/email_account/email_account.py:153 msgid "You need to set one IMAP folder for {0}" msgstr "" @@ -29837,7 +29907,7 @@ msgstr "" msgid "text in document type" msgstr "" -#: public/js/frappe/form/controls/data.js:35 +#: public/js/frappe/form/controls/data.js:36 msgid "this form" msgstr "" @@ -29882,7 +29952,7 @@ msgstr "" msgid "via Google Meet" msgstr "" -#: email/doctype/notification/notification.py:216 +#: email/doctype/notification/notification.py:220 msgid "via Notification" msgstr "" @@ -29950,12 +30020,12 @@ msgstr "" msgid "{0} ${type}" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:79 +#: public/js/frappe/data_import/data_exporter.js:80 #: public/js/frappe/views/gantt/gantt_view.js:54 msgid "{0} ({1})" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:76 +#: public/js/frappe/data_import/data_exporter.js:77 msgid "{0} ({1}) (1 row mandatory)" msgstr "" @@ -30005,7 +30075,7 @@ msgstr "" #: public/js/frappe/ui/toolbar/search_utils.js:83 #: public/js/frappe/ui/toolbar/search_utils.js:84 #: public/js/frappe/utils/utils.js:924 -#: public/js/frappe/widgets/chart_widget.js:317 www/list.html:4 www/list.html:8 +#: public/js/frappe/widgets/chart_widget.js:318 www/list.html:4 www/list.html:8 msgid "{0} List" msgstr "" @@ -30032,7 +30102,7 @@ msgstr "" #: public/js/frappe/ui/toolbar/search_utils.js:95 #: public/js/frappe/ui/toolbar/search_utils.js:96 #: public/js/frappe/utils/utils.js:921 -#: public/js/frappe/widgets/chart_widget.js:325 +#: public/js/frappe/widgets/chart_widget.js:326 msgid "{0} Report" msgstr "" @@ -30065,7 +30135,7 @@ msgstr "" msgid "{0} added" msgstr "" -#: public/js/frappe/form/controls/data.js:203 +#: public/js/frappe/form/controls/data.js:204 msgid "{0} already exists. Select another name" msgstr "" @@ -30270,7 +30340,7 @@ msgstr "" msgid "{0} has left the conversation in {1} {2}" msgstr "" -#: __init__.py:2493 +#: __init__.py:2499 msgid "{0} has no versions tracked." msgstr "" @@ -30336,7 +30406,7 @@ msgstr "" msgid "{0} is like {1}" msgstr "" -#: email/doctype/email_account/email_account.py:176 +#: email/doctype/email_account/email_account.py:186 msgid "{0} is mandatory" msgstr "" @@ -30416,7 +30486,7 @@ msgstr "" msgid "{0} is one of {1}" msgstr "" -#: email/doctype/email_account/email_account.py:277 model/naming.py:217 +#: email/doctype/email_account/email_account.py:293 model/naming.py:217 #: printing/doctype/print_format/print_format.py:91 utils/csvutils.py:153 msgid "{0} is required" msgstr "" @@ -30429,11 +30499,11 @@ msgstr "" msgid "{0} is within {1}" msgstr "" -#: public/js/frappe/list/list_view.js:1601 +#: public/js/frappe/list/list_view.js:1653 msgid "{0} items selected" msgstr "" -#: core/doctype/user/user.py:1328 +#: core/doctype/user/user.py:1336 msgid "{0} just impersonated as you. They gave this reason: {1}" msgstr "" @@ -30500,11 +30570,11 @@ msgstr "" msgid "{0} not found" msgstr "" -#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:992 +#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:1027 msgid "{0} of {1}" msgstr "" -#: public/js/frappe/list/list_view.js:994 +#: public/js/frappe/list/list_view.js:1029 msgid "{0} of {1} ({2} rows with children)" msgstr "" @@ -30537,7 +30607,7 @@ msgstr "" msgid "{0} records deleted" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:228 +#: public/js/frappe/data_import/data_exporter.js:229 msgid "{0} records will be exported" msgstr "" @@ -30685,7 +30755,7 @@ msgstr "" msgid "{0} {1} not found" msgstr "" -#: model/delete_doc.py:242 +#: model/delete_doc.py:251 msgid "{0} {1}: Submitted Record cannot be deleted. You must {2} Cancel {3} it first." msgstr "" @@ -30777,7 +30847,7 @@ msgstr "" msgid "{0}: Permission at level 0 must be set before higher levels are set" msgstr "" -#: public/js/frappe/form/controls/data.js:50 +#: public/js/frappe/form/controls/data.js:51 msgid "{0}: You can increase the limit for the field if required via {1}" msgstr "" @@ -30861,8 +30931,8 @@ msgstr "" msgid "{} field cannot be empty." msgstr "" -#: email/doctype/email_account/email_account.py:200 -#: email/doctype/email_account/email_account.py:208 +#: email/doctype/email_account/email_account.py:216 +#: email/doctype/email_account/email_account.py:224 msgid "{} has been disabled. It can only be enabled if {} is checked." msgstr "" From 259870536450cab45337a8a2b94f407f32895efc Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Sun, 14 Jul 2024 22:45:05 +0530 Subject: [PATCH 090/176] fix: Swedish translations --- frappe/locale/sv.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po index 0e9ee42c93..f9bd261dfa 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: 2024-07-07 09:33+0000\n" -"PO-Revision-Date: 2024-07-13 17:16\n" +"PO-Revision-Date: 2024-07-14 17:15\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Swedish\n" "MIME-Version: 1.0\n" @@ -16120,7 +16120,7 @@ msgstr "Ny {0}: {1}" #: utils/change_log.py:373 msgid "New {} releases for the following apps are available" -msgstr "Nya {} utgåvor för följande appar finns tillgängliga" +msgstr "Nya {} versioner för följande appar finns tillgängliga" #: core/doctype/user/user.py:753 msgid "Newly created user {0} has no roles enabled." From 84919bfe8e5ae291970899ab50165e6953ec88ff Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 15 Jul 2024 09:25:08 +0200 Subject: [PATCH 091/176] fix: Typing hint for Document.get_doc_before_save --- frappe/model/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 01278775b3..8e7d4a7f54 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -458,7 +458,7 @@ class Document(BaseDocument): d: Document d.db_update() - def get_doc_before_save(self) -> "Document": + def get_doc_before_save(self) -> "Self": return getattr(self, "_doc_before_save", None) def has_value_changed(self, fieldname): From 3491f9d88acf4fc89bdfb3bb20964d65c8ac609a Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Mon, 15 Jul 2024 20:21:22 +0530 Subject: [PATCH 092/176] chore: add warning for workflow actions email --- frappe/templates/emails/workflow_action.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/templates/emails/workflow_action.html b/frappe/templates/emails/workflow_action.html index 51ec9b6c01..9cc6359244 100644 --- a/frappe/templates/emails/workflow_action.html +++ b/frappe/templates/emails/workflow_action.html @@ -5,4 +5,7 @@ {{_(action.action_name)}} {% endfor %}

    +
    + {{ _("The contents of this email are strictly confidential. Please do not forward this email to anyone.") }} +
    \ No newline at end of file From e04b944d3af3292d69f452e370415c930ebc49b8 Mon Sep 17 00:00:00 2001 From: Poorvi-R-Bhat Date: Tue, 16 Jul 2024 09:32:11 +0530 Subject: [PATCH 093/176] fix: link fields were not displaying the dropdown values in the portal#18421 --- frappe/public/js/frappe/form/controls/link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index 86b30757d7..62e5e4de67 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -255,7 +255,7 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat doctype: doctype, ignore_user_permissions: me.df.ignore_user_permissions, reference_doctype: me.get_reference_doctype() || "", - page_length: cint(frappe.boot.sysdefaults.link_field_results_limit) || 10, + page_length: cint(frappe.boot.sysdefaults?.link_field_results_limit) || 10, }; me.set_custom_query(args); From f5fbca26f9b58c14645d81ee6551a4bb9dd6d222 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Tue, 16 Jul 2024 14:00:02 +0530 Subject: [PATCH 094/176] fix(multiselect_list): don't crash if a value with space is selected Spaces or certain other characters don't seem to be well handled by jQuery, so escape the value before checking. Signed-off-by: Akhil Narang --- frappe/public/js/frappe/form/controls/multiselect_list.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/multiselect_list.js b/frappe/public/js/frappe/form/controls/multiselect_list.js index 7ccde751ca..0e6198085a 100644 --- a/frappe/public/js/frappe/form/controls/multiselect_list.js +++ b/frappe/public/js/frappe/form/controls/multiselect_list.js @@ -139,7 +139,7 @@ frappe.ui.form.ControlMultiSelectList = class ControlMultiSelectList extends ( //Unselect old values this.values.forEach((value) => { this.$list_wrapper - .find(`.selectable-item[data-value=${value}]`) + .find(`.selectable-item[data-value=${CSS.escape(value)}]`) .toggleClass("selected"); }); this.values = value; @@ -147,7 +147,7 @@ frappe.ui.form.ControlMultiSelectList = class ControlMultiSelectList extends ( this.update_selected_values(value); //Select new values this.$list_wrapper - .find(`.selectable-item[data-value=${value}]`) + .find(`.selectable-item[data-value=${CSS.escape(value)}]`) .toggleClass("selected"); }); this.parse_validate_and_set_in_model(""); From 1fe0f6e20b4b01f66615aa8da9376f1daeb31991 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:15:43 +0200 Subject: [PATCH 095/176] fix: handle invalid images in HTML (#27095) * fix: handle invalid image * refactor: simplify broken image replacement * fix: add alt attribute to broken image --- frappe/core/doctype/file/test_file.py | 21 ++++++++++++++++++++- frappe/core/doctype/file/utils.py | 12 +++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py index 6c9b9f5872..03a8927dac 100644 --- a/frappe/core/doctype/file/test_file.py +++ b/frappe/core/doctype/file/test_file.py @@ -17,7 +17,7 @@ from frappe.core.api.file import ( unzip_file, ) from frappe.core.doctype.file.exceptions import FileTypeNotAllowed -from frappe.core.doctype.file.utils import get_extension +from frappe.core.doctype.file.utils import get_corrupted_image_msg, get_extension from frappe.desk.form.utils import add_comment from frappe.exceptions import ValidationError from frappe.tests.utils import FrappeTestCase, change_settings @@ -768,6 +768,25 @@ class TestFileUtils(FrappeTestCase): ) self.assertRegex(communication.content, r"") + def test_broken_image(self): + """Ensure that broken inline images don't cause errors.""" + is_private = not frappe.get_meta("Communication").make_attachments_public + communication = frappe.get_doc( + doctype="Communication", + communication_type="Communication", + communication_medium="Email", + content='
    ', + recipients="to ", + cc=None, + bcc=None, + sender="sender@test.com", + ).insert(ignore_permissions=True) + + self.assertFalse( + frappe.db.exists("File", {"attached_to_name": communication.name, "is_private": is_private}) + ) + self.assertIn(f'{get_corrupted_image_msg()}', communication.content) + def test_create_new_folder(self): folder = create_new_folder("test_folder", "Home") self.assertTrue(folder.is_folder) diff --git a/frappe/core/doctype/file/utils.py b/frappe/core/doctype/file/utils.py index 578c760389..d16f76b090 100644 --- a/frappe/core/doctype/file/utils.py +++ b/frappe/core/doctype/file/utils.py @@ -2,6 +2,7 @@ import hashlib import mimetypes import os import re +from binascii import Error as BinasciiError from io import BytesIO from typing import TYPE_CHECKING, Optional from urllib.parse import unquote @@ -234,7 +235,12 @@ def extract_images_from_html(doc: "Document", content: str, is_private: bool = F content = content.encode("utf-8") if b"," in content: content = content.split(b",")[1] - content = safe_b64decode(content) + + try: + content = safe_b64decode(content) + except BinasciiError: + frappe.flags.has_dataurl = True + return f'{get_corrupted_image_msg()} str: extn = None if content_type: From 171792f8fc8aeea3be0722e6c1fc427af77f8e4a Mon Sep 17 00:00:00 2001 From: gavin Date: Tue, 16 Jul 2024 14:18:13 +0200 Subject: [PATCH 096/176] feat: frm.set_headline_alert permanent (#27097) Allow option to set a permanent headline on form. For when you want a user to always be warned. --- frappe/public/js/frappe/form/dashboard.js | 10 +++++----- frappe/public/js/frappe/form/layout.js | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index 6efcdd3079..d1a2fde9d2 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -633,8 +633,8 @@ frappe.ui.form.Dashboard = class FormDashboard { } // TODO: Review! code related to headline should be the part of layout/form - set_headline(html, color) { - this.frm.layout.show_message(html, color); + set_headline(html, color, permanent = false) { + this.frm.layout.show_message(html, color, permanent); } clear_headline() { @@ -642,7 +642,7 @@ frappe.ui.form.Dashboard = class FormDashboard { } add_comment(text, alert_class, permanent) { - this.set_headline_alert(text, alert_class); + this.set_headline_alert(text, alert_class, permanent); if (!permanent) { setTimeout(() => { this.clear_headline(); @@ -654,9 +654,9 @@ frappe.ui.form.Dashboard = class FormDashboard { this.clear_headline(); } - set_headline_alert(text, color) { + set_headline_alert(text, color, permanent = false) { if (text) { - this.set_headline(`
    ${text}
    `, color); + this.set_headline(`
    ${text}
    `, color, permanent); } else { this.clear_headline(); } diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index d761403489..038e3c55ef 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -97,7 +97,7 @@ frappe.ui.form.Layout = class Layout { return fields; } - show_message(html, color) { + show_message(html, color, permanent = false) { if (this.message_color) { // remove previous color this.message.removeClass(this.message_color); @@ -112,8 +112,10 @@ frappe.ui.form.Layout = class Layout { } this.message.removeClass("hidden").addClass(this.message_color); $(html).appendTo(this.message); - close_message.appendTo(this.message); - close_message.on("click", () => this.message.empty().addClass("hidden")); + if (!permanent) { + close_message.appendTo(this.message); + close_message.on("click", () => this.message.empty().addClass("hidden")); + } } else { this.message.empty().addClass("hidden"); } From 5e95e5121995eb858401bacb637d27389f7958ba Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Tue, 16 Jul 2024 18:06:58 +0530 Subject: [PATCH 097/176] fix: don't trigger `Value Change` notifications for deleted documents Signed-off-by: Akhil Narang --- frappe/model/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 72a491d039..d216aebacc 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -1031,7 +1031,7 @@ class Document(BaseDocument): "on_cancel": "Cancel", } - if not self.flags.in_insert: + if not self.flags.in_insert and not self.flags.in_delete: # value change is not applicable in insert event_map["on_change"] = "Value Change" From f2904fb0db87c5a12c927380850d7eeb80f5148a Mon Sep 17 00:00:00 2001 From: RJPvT <48353029+RJPvT@users.noreply.github.com> Date: Sat, 13 Jul 2024 20:54:15 +0200 Subject: [PATCH 098/176] fix: not showing actions menu should be .list-row-checkbox:checked (since three months ago) (cherry picked from commit 77d31e04c4c0962163f54fd34b2e85105b98fe3c) --- frappe/public/js/frappe/list/list_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 1acd6b1347..4fa7dd8401 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -544,7 +544,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { toggle_result_area() { super.toggle_result_area(); - this.toggle_actions_menu_button(this.$result.find(".list-row-check:checked").length > 0); + this.toggle_actions_menu_button(this.$result.find(".list-row-checkbox:checked").length > 0); } toggle_actions_menu_button(toggle) { From 04e3f1d035017369a06a056ddca6c0ddacb6d9e3 Mon Sep 17 00:00:00 2001 From: RJPvT <48353029+RJPvT@users.noreply.github.com> Date: Sat, 13 Jul 2024 21:04:16 +0200 Subject: [PATCH 099/176] fix: makeup prettier (cherry picked from commit 979a7659c9ee83139ff517802537cf6571e4ef4b) --- frappe/public/js/frappe/list/list_view.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 4fa7dd8401..c904dd7544 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -544,7 +544,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { toggle_result_area() { super.toggle_result_area(); - this.toggle_actions_menu_button(this.$result.find(".list-row-checkbox:checked").length > 0); + this.toggle_actions_menu_button( + this.$result.find(".list-row-checkbox:checked").length > 0 + ); } toggle_actions_menu_button(toggle) { From ffcd6d1ff5569abc82db4453b8e75353412f6953 Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Tue, 16 Jul 2024 22:52:31 +0200 Subject: [PATCH 100/176] fix: Added missing newlines after merge (for pre-commit checks) --- frappe/tests/test_db.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index d4ccb78d65..63c0dba7da 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -1080,6 +1080,7 @@ class TestSqlIterator(FrappeTestCase): with frappe.db.unbuffered_cursor(): self.test_db_sql_iterator() + class ExtFrappeTestCase(FrappeTestCase): def assertSqlException(self): class SqlExceptionContextManager: @@ -1259,6 +1260,7 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): del frappe.conf["db_schema"] + class TestDbConnectWithEnvCredentials(FrappeTestCase): current_site = frappe.local.site From 7ffe82956d52c94333732041c43cce174c4b99c7 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 17 Jul 2024 14:12:59 +0530 Subject: [PATCH 101/176] chore(deps): pin pydyf to 0.10.0 weasyprint had a loose requirement of >=0.6.0 earlier pydyf changed their constructor in 0.11.0 Later versions of weasyprint would work (they did pin their dependencies, but there's still a conflict due to `bleach[css]` The conflict is caused by: weasyprint 62.3 depends on tinycss2>=1.3.0 bleach[css] 6.0.0 depends on tinycss2<1.2 and >=1.1.0; extra == "css" For now, pinning this is the simplest solution until we upgrade other packages as well Signed-off-by: Akhil Narang --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 6b27020480..242a09f54d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ dependencies = [ "PyYAML~=6.0.1", "RestrictedPython~=7.0", "WeasyPrint==59.0", + "pydyf==0.10.0", "Werkzeug~=3.0.1", "Whoosh~=2.7.4", "beautifulsoup4~=4.12.2", From eb28a7322bcf50e003db59aa962e7d8a4adbcb5c Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 17 Jul 2024 13:20:09 +0200 Subject: [PATCH 102/176] fix(Email Account): handle errors during error handling --- frappe/email/doctype/email_account/email_account.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index bffccfd07f..aac4a97587 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -599,10 +599,15 @@ class EmailAccount(Document): frappe.db.rollback() except Exception: frappe.db.rollback() - self.log_error(title="EmailAccount.receive") - if self.use_imap: - self.handle_bad_emails(mail.uid, mail.raw_message, frappe.get_traceback()) - exceptions.append(frappe.get_traceback()) + try: + self.log_error(title="EmailAccount.receive") + if self.use_imap: + self.handle_bad_emails(mail.uid, mail.raw_message, frappe.get_traceback()) + exceptions.append(frappe.get_traceback()) + except Exception: + frappe.db.rollback() + else: + frappe.db.commit() else: frappe.db.commit() From 029e6f7dddc0c74e403bbdc7fb98b97d6f96a796 Mon Sep 17 00:00:00 2001 From: Poorvi-R-Bhat Date: Tue, 16 Jul 2024 22:59:34 +0530 Subject: [PATCH 103/176] fix: disabling the notifications when the user is disabled#18193 --- frappe/core/doctype/user/user.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 3269d2860e..bc339432ec 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -182,6 +182,12 @@ class User(Document): if (self.name not in ["Administrator", "Guest"]) and (not self.get_social_login_userid("frappe")): self.set_social_login_userid("frappe", frappe.generate_hash(length=39)) + def disable_email_fields_if_user_disabled(self): + if not self.enabled: + self.thread_notify = 0 + self.send_me_a_copy = 0 + self.allowed_in_mentions = 0 + @frappe.whitelist() def populate_role_profile_roles(self): if not self.role_profiles: @@ -284,6 +290,7 @@ class User(Document): # toggle notifications based on the user's status toggle_notifications(self.name, enable=cint(self.enabled), ignore_permissions=True) + self.disable_email_fields_if_user_disabled() def email_new_password(self, new_password=None): if new_password and not self.flags.in_insert: From 4b7683d0447fd4ca3b2f210c60494022409fb18d Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 17 Jul 2024 19:11:52 +0530 Subject: [PATCH 104/176] fix: disabled users now have `thread_notify` disabled Signed-off-by: Akhil Narang --- frappe/core/doctype/communication/test_communication.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/communication/test_communication.py b/frappe/core/doctype/communication/test_communication.py index 3d42c823c5..4c9e3650ac 100644 --- a/frappe/core/doctype/communication/test_communication.py +++ b/frappe/core/doctype/communication/test_communication.py @@ -380,7 +380,8 @@ class TestCommunicationEmailMixin(FrappeTestCase): user = self.new_user(email="bcc+2@test.com", enabled=0) comm = self.new_communication(bcc=bcc_list) res = comm.get_mail_bcc_with_displayname() - self.assertCountEqual(res, bcc_list) + # Disabled users have thread_notify disabled, so they'll be removed from the list + self.assertCountEqual(res, bcc_list[:1]) user.delete() comm.delete() From 806d13dbb9eaf80fcaf62262eba9f91d8f4fb49d Mon Sep 17 00:00:00 2001 From: Jeroen Peperkamp Date: Wed, 17 Jul 2024 23:44:58 +0800 Subject: [PATCH 105/176] fix!: sort exported customizations by name for better diffs (#26927) * fix: sort exported customizations by name for better diffs * fix formatting --------- Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com> --- frappe/modules/utils.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frappe/modules/utils.py b/frappe/modules/utils.py index adcc55e4a8..2c034d3bbf 100644 --- a/frappe/modules/utils.py +++ b/frappe/modules/utils.py @@ -64,16 +64,20 @@ def export_customizations( frappe.throw(_("Only allowed to export customizations in developer mode")) custom = { - "custom_fields": frappe.get_all("Custom Field", fields="*", filters={"dt": doctype}), - "property_setters": frappe.get_all("Property Setter", fields="*", filters={"doc_type": doctype}), + "custom_fields": frappe.get_all("Custom Field", fields="*", filters={"dt": doctype}, order_by="name"), + "property_setters": frappe.get_all( + "Property Setter", fields="*", filters={"doc_type": doctype}, order_by="name" + ), "custom_perms": [], - "links": frappe.get_all("DocType Link", fields="*", filters={"parent": doctype}), + "links": frappe.get_all("DocType Link", fields="*", filters={"parent": doctype}, order_by="name"), "doctype": doctype, "sync_on_migrate": sync_on_migrate, } if with_permissions: - custom["custom_perms"] = frappe.get_all("Custom DocPerm", fields="*", filters={"parent": doctype}) + custom["custom_perms"] = frappe.get_all( + "Custom DocPerm", fields="*", filters={"parent": doctype}, order_by="name" + ) # also update the custom fields and property setters for all child tables for d in frappe.get_meta(doctype).get_table_fields(): From 02c680e68dbd60fbf53dbf2264eabba41a9340f6 Mon Sep 17 00:00:00 2001 From: "Arun Mathai S.K." <61804369+arunmathaisk@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:27:20 +0530 Subject: [PATCH 106/176] fix: migrate-to now works (#27115) * chore : migrat-to pre check url * feat: migrate-to now works * fix: unecessary context * chore: remove commented code --- frappe/commands/site.py | 11 ++--------- frappe/integrations/frappe_providers/__init__.py | 11 +++-------- frappe/integrations/frappe_providers/frappecloud.py | 13 ++++++++----- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/frappe/commands/site.py b/frappe/commands/site.py index e76f0c23d0..27fd289f47 100644 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -675,19 +675,12 @@ def migrate(context, skip_failing=False, skip_search_index=False): @click.command("migrate-to") -@click.argument("frappe_provider") @pass_context -def migrate_to(context, frappe_provider): +def migrate_to(context): "Migrates site to the specified provider" from frappe.integrations.frappe_providers import migrate_to - for site in context.sites: - frappe.init(site=site) - frappe.connect() - migrate_to(site, frappe_provider) - frappe.destroy() - if not context.sites: - raise SiteNotSpecifiedError + migrate_to(context) @click.command("run-patch") diff --git a/frappe/integrations/frappe_providers/__init__.py b/frappe/integrations/frappe_providers/__init__.py index 630c2c08b4..b1f0c41798 100644 --- a/frappe/integrations/frappe_providers/__init__.py +++ b/frappe/integrations/frappe_providers/__init__.py @@ -1,13 +1,8 @@ # imports - standard imports -import sys - # imports - module imports + from frappe.integrations.frappe_providers.frappecloud import frappecloud_migrator -def migrate_to(local_site, frappe_provider): - if frappe_provider in ("frappe.cloud", "frappecloud.com"): - return frappecloud_migrator(local_site) - else: - print(f"{frappe_provider} is not supported yet") - sys.exit(1) +def migrate_to(): + return frappecloud_migrator() diff --git a/frappe/integrations/frappe_providers/frappecloud.py b/frappe/integrations/frappe_providers/frappecloud.py index f276004427..499f05e920 100644 --- a/frappe/integrations/frappe_providers/frappecloud.py +++ b/frappe/integrations/frappe_providers/frappecloud.py @@ -5,10 +5,9 @@ import frappe from frappe.core.utils import html2text -def frappecloud_migrator(local_site): +def get_remote_script(remote_site): print("Retrieving Site Migrator...") - remote_site = frappe.conf.frappecloud_url or "frappecloud.com" - request_url = f"https://{remote_site}/api/method/press.api.script" + request_url = f"http://{remote_site}/api/method/press.api.script" request = requests.get(request_url) if request.status_code / 100 != 2: @@ -19,8 +18,12 @@ def frappecloud_migrator(local_site): ) return - script_contents = request.json()["message"] + return request.json()["message"] + +def frappecloud_migrator(): + remote_site_name = "frappecloud.com" + script_contents = get_remote_script(remote_site=remote_site_name) import os import sys import tempfile @@ -29,4 +32,4 @@ def frappecloud_migrator(local_site): script = tempfile.NamedTemporaryFile(mode="w") script.write(script_contents) print(f"Site Migrator stored at {script.name}") - os.execv(py, [py, script.name, local_site]) + os.execv(py, [py, script.name]) From 3354fe9db470ee101c6f2240fd22f7ccc4d5d1e5 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Thu, 18 Jul 2024 11:36:15 +0530 Subject: [PATCH 107/176] fix(newsletter): prevent `UnboundLocalError` when `doc` is not associated with a value Signed-off-by: Akhil Narang --- frappe/email/doctype/newsletter/newsletter.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/email/doctype/newsletter/newsletter.py b/frappe/email/doctype/newsletter/newsletter.py index 45d5c35d99..5b39a00d7e 100644 --- a/frappe/email/doctype/newsletter/newsletter.py +++ b/frappe/email/doctype/newsletter/newsletter.py @@ -439,7 +439,11 @@ def newsletter_email_read(recipient_email=None, reference_doctype=None, referenc ).run() except Exception: - doc.log_error(f"Unable to mark as viewed for {recipient_email}") + frappe.log_error( + title=f"Unable to mark as viewed for {recipient_email}", + reference_doctype="Newsletter", + reference_name=reference_name, + ) finally: frappe.response.update(frappe.utils.get_imaginary_pixel_response()) From 4a4e25f9887b0b1e1fb8b43bdd48c88c0865683a Mon Sep 17 00:00:00 2001 From: David Date: Thu, 18 Jul 2024 11:48:17 +0200 Subject: [PATCH 108/176] style: format --- frappe/email/doctype/notification/notification.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index ae915759c0..9725846496 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -600,6 +600,7 @@ def get_reference_doctype(doc): def get_reference_name(doc): return doc.parent if doc.meta.istable else doc.name + def _parse_receiver_by_document_field(s): fragments = s.split(",") # fields from child table or linked doctype From b2a3102345c948d068828e4c8c264d38261805de Mon Sep 17 00:00:00 2001 From: David Date: Tue, 21 May 2024 20:05:08 +0200 Subject: [PATCH 109/176] feat(notifications): add preview --- .../doctype/notification/notification.js | 12 +++ .../doctype/notification/notification.py | 54 ++++++++++ frappe/public/js/form.bundle.js | 1 + .../public/js/frappe/views/render_preview.js | 100 ++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 frappe/public/js/frappe/views/render_preview.js diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js index bede0b429b..9db656c924 100644 --- a/frappe/email/doctype/notification/notification.js +++ b/frappe/email/doctype/notification/notification.js @@ -146,6 +146,7 @@ frappe.ui.form.on("Notification", { }, }; }); + frm.preview_fields = frm.doc.__onload.preview_fields; }, refresh: function (frm) { frappe.notification.setup_fieldname_select(frm); @@ -161,6 +162,17 @@ frappe.ui.form.on("Notification", { }); frm.get_field("is_standard").toggle(frappe.boot.developer_mode); frm.trigger("event"); + if (frm.doc.document_type) { + frm.add_custom_button(__("Preview"), () => { + const args = { + doc: frm.doc, + doctype: frm.doc.document_type, + preview_fields: frm.preview_fields, + }; + let dialog = new frappe.views.RenderPreviewer(args); + return dialog; + }); + } }, document_type: function (frm) { frappe.notification.setup_fieldname_select(frm); diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index c9e9f44a53..78aa47a2b2 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -73,11 +73,65 @@ class Notification(Document): """load message""" if self.is_standard: self.message = self.get_template() + self.set_onload( + "preview_fields", + [ + {"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"}, + {"label": _("Subject"), "fieldtype": "Data", "method": "preview_subject"}, + {"label": _("Message"), "fieldtype": "Code", "method": "preview_message"}, + ], + ) def autoname(self): if not self.name: self.name = self.subject + # START: PreviewRenderer API + + @frappe.whitelist() + def preview_meets_condition(self, preview_document): + if not self.condition: + return _("Yes") + try: + doc = frappe.get_cached_doc(self.document_type, preview_document) + return _("Yes") if frappe.safe_eval(self.condition, eval_locals=get_context(doc)) else _("No") + except Exception as e: + frappe.local.message_log = [] + return _("Failed to evaluate conditions: {}").format(e) + + @frappe.whitelist() + def preview_message(self, preview_document): + try: + doc = frappe.get_cached_doc(self.document_type, preview_document) + context = get_context(doc) + context.update({"alert": self, "comments": None}) + if doc.get("_comments"): + context["comments"] = json.loads(doc.get("_comments")) + msg = frappe.render_template(self.message, context) + if self.channel == "SMS": + return frappe.utils.strip_html_tags(msg) + return msg + except Exception as e: + return _("Failed to render message: {}").format(e) + + @frappe.whitelist() + def preview_subject(self, preview_document): + try: + doc = frappe.get_cached_doc(self.document_type, preview_document) + context = get_context(doc) + context.update({"alert": self, "comments": None}) + if doc.get("_comments"): + context["comments"] = json.loads(doc.get("_comments")) + if not self.subject: + return _("No subject") + if "{" in self.subject: + return frappe.render_template(self.subject, context) + return self.subject + except Exception as e: + return _("Failed to render subject: {}").format(e) + + # END: PreviewRenderer API + def validate(self): if self.channel in ("Email", "Slack", "System Notification"): validate_template(self.subject) diff --git a/frappe/public/js/form.bundle.js b/frappe/public/js/form.bundle.js index f2d19f5f3b..84af6d3f60 100644 --- a/frappe/public/js/form.bundle.js +++ b/frappe/public/js/form.bundle.js @@ -11,6 +11,7 @@ import "./frappe/form/templates/timeline_message_box.html"; import "./frappe/form/templates/users_in_sidebar.html"; import "./frappe/views/formview.js"; +import "./frappe/views/render_preview.js"; import "./frappe/form/form.js"; import "./frappe/meta_tag.js"; import "./frappe/doctype/"; diff --git a/frappe/public/js/frappe/views/render_preview.js b/frappe/public/js/frappe/views/render_preview.js new file mode 100644 index 0000000000..a1d5348b52 --- /dev/null +++ b/frappe/public/js/frappe/views/render_preview.js @@ -0,0 +1,100 @@ +// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +// MIT License. See license.txt +frappe.provide("frappe.views"); + +frappe.views.RenderPreviewer = class RenderPreviewer { + constructor(opts) { + $.extend(this, opts); + this.make(); + } + + make() { + let me = this; + + me.set_fields(); + let fields = me.header_fields; + fields.push(...me.body_fields); + + me.dialog = new frappe.ui.Dialog({ + title: __("Preview on") + " " + __(me.doctype), + no_submit_on_enter: true, + fields: fields, + minimizable: true, + size: "large", + }); + + me.prepare(); + me.dialog.show(); + } + + set_fields() { + let me = this; + me.header_fields = [ + { + label: __("Reference Doctype"), + fieldtype: "Link", + fieldname: "doctype", + reqd: 1, + read_only: 1, + hidden: 1, + }, + { + label: __("Document"), + fieldtype: "Dynamic Link", + fieldname: "preview_document", + options: "doctype", + reqd: 1, + onchange: () => me.render_previews(), + }, + ]; + me.body_fields = [{ fieldtype: "Section Break" }]; + + me.preview_fields.forEach((spec) => { + let field = { + label: spec.label, + fieldtype: spec.fieldtype, + fieldname: spec.method, + read_only: 1, + }; + if (spec.method === "preview_meets_condition") { + me.header_fields.push({ fieldtype: "Column Break" }); + me.header_fields.push(field); + } else { + me.body_fields.push(field); + } + }); + } + + prepare() { + let me = this; + me.dialog.set_values({ + doctype: me.doctype, + }); + } + async render_previews() { + let me = this; + let preview_document = me.dialog.get_value("preview_document"); + if (preview_document) { + let promises = []; + me.preview_fields.forEach((spec) => { + let fieldname = spec.method; + promises.push( + frappe + .xcall("run_doc_method", { + dt: me.doc.doctype, + dn: me.doc.name, + method: spec.method, + arg: preview_document, + }) + .then((message) => me.dialog.set_value(fieldname, message)) + ); + }); + await Promise.all(promises); + } else { + me.preview_fields.forEach((spec) => { + let fieldname = spec.method; + me.dialog.set_value(fieldname, null); + }); + } + } +}; From f3fce843c625db583df54f677ffcb43288bb5de5 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 1 Jul 2024 22:06:02 +0200 Subject: [PATCH 110/176] fix(notification): preview from standard notification --- frappe/email/doctype/notification/notification.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index 78aa47a2b2..d570c80b6b 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -94,7 +94,10 @@ class Notification(Document): return _("Yes") try: doc = frappe.get_cached_doc(self.document_type, preview_document) - return _("Yes") if frappe.safe_eval(self.condition, eval_locals=get_context(doc)) else _("No") + context = get_context(doc) + if self.is_standard: + self.load_standard_properties(context) + return _("Yes") if frappe.safe_eval(self.condition, eval_locals=context) else _("No") except Exception as e: frappe.local.message_log = [] return _("Failed to evaluate conditions: {}").format(e) @@ -107,6 +110,8 @@ class Notification(Document): context.update({"alert": self, "comments": None}) if doc.get("_comments"): context["comments"] = json.loads(doc.get("_comments")) + if self.is_standard: + self.load_standard_properties(context) msg = frappe.render_template(self.message, context) if self.channel == "SMS": return frappe.utils.strip_html_tags(msg) @@ -122,6 +127,8 @@ class Notification(Document): context.update({"alert": self, "comments": None}) if doc.get("_comments"): context["comments"] = json.loads(doc.get("_comments")) + if self.is_standard: + self.load_standard_properties(context) if not self.subject: return _("No subject") if "{" in self.subject: From 053ad462804ca4566e57b04220ab1dc8a10fce1e Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:12:18 +0200 Subject: [PATCH 111/176] fix: skip redundant fields in fixture export (#27048) --- frappe/core/doctype/data_import/data_import.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/data_import/data_import.py b/frappe/core/doctype/data_import/data_import.py index b2de0badc9..0af57c2dd2 100644 --- a/frappe/core/doctype/data_import/data_import.py +++ b/frappe/core/doctype/data_import/data_import.py @@ -296,7 +296,16 @@ def export_json(doctype, path, filters=None, or_filters=None, name=None, order_b for v in doc.values(): if isinstance(v, list): for child in v: - for key in (*del_keys, "docstatus", "doctype", "modified", "name"): + for key in ( + *del_keys, + "docstatus", + "doctype", + "modified", + "name", + "parent", + "parentfield", + "parenttype", + ): if key in child: del child[key] From 284af156e07b4fda0129097222d089a0a7d43bc9 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Thu, 18 Jul 2024 21:17:14 +0200 Subject: [PATCH 112/176] fix: refresh fields after `frm.set_read_only` (#26998) --- frappe/public/js/frappe/form/form.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 7edf8544cc..bd74ee5bd1 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -418,7 +418,7 @@ frappe.ui.form.Form = class FrappeForm { // read only (workflow) this.read_only = frappe.workflow.is_read_only(this.doctype, this.docname); if (this.read_only) { - this.set_read_only(true); + this.set_read_only(); frappe.show_alert(__("This form is not editable due to a Workflow.")); } @@ -671,6 +671,10 @@ frappe.ui.form.Form = class FrappeForm { } refresh_fields() { + if (this.layout === undefined) { + return; + } + this.layout.refresh(this.doc); this.layout.primary_button = this.$wrapper.find(".btn-primary"); @@ -1843,6 +1847,7 @@ frappe.ui.form.Form = class FrappeForm { email: p.email, }; }); + this.refresh_fields(); } trigger(event, doctype, docname) { From 60e145ea12dbb0ae369c099a5f544a65b385f459 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Fri, 19 Jul 2024 15:37:03 +0530 Subject: [PATCH 113/176] fix: check df options for determining currency even if no doc is passed We can get data like `Company` from user defaults Signed-off-by: Akhil Narang --- frappe/public/js/frappe/model/meta.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/model/meta.js b/frappe/public/js/frappe/model/meta.js index 2f209e048d..8253f1974f 100644 --- a/frappe/public/js/frappe/model/meta.js +++ b/frappe/public/js/frappe/model/meta.js @@ -286,13 +286,19 @@ $.extend(frappe.meta, { if (!doc && cur_frm) doc = cur_frm.doc; if (df && df.options) { - if (doc && df.options.indexOf(":") != -1) { + if (df.options.indexOf(":") != -1) { var options = df.options.split(":"); if (options.length == 3) { - // get reference record e.g. Company - var docname = doc[options[1]]; - if (!docname && cur_frm) { - docname = cur_frm.doc[options[1]]; + let docname = null; + if (doc) { + // get reference record e.g. Company + docname = doc[options[1]]; + if (!docname && cur_frm) { + docname = cur_frm.doc[options[1]]; + } + } else { + // Try to get default value, useful for cases like Company overridden in session defaults + docname = frappe.defaults.get_user_default(options[1]); } currency = frappe.model.get_value(options[0], docname, options[2]) || From e2a1c506feb36f4919eabaca41824537c94ca6c3 Mon Sep 17 00:00:00 2001 From: Philipp Gruener Date: Sat, 20 Jul 2024 13:23:03 +0200 Subject: [PATCH 114/176] fix: Added adjustments --- frappe/database/postgres/database.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index caba53e242..56ae71a9ad 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -172,7 +172,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): @property def db_schema(self): - return re.sub(r'["\']', "", frappe.conf.get("db_schema", "public")) + return frappe.conf.get("db_schema", "public").replace("'", "").replace('"', "") def connect(self): super().connect() @@ -247,22 +247,22 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def get_db_table_columns(self, table) -> list[str]: """Returns list of column names from given table.""" - columns = frappe.cache.hget("table_columns", table) - if columns is None: - information_schema = frappe.qb.Schema("information_schema") + if (columns := frappe.cache.hget("table_columns", table)) is not None: + return columns - columns = ( - frappe.qb.from_(information_schema.columns) - .select(information_schema.columns.column_name) - .where( - (information_schema.columns.table_name == table) - & (information_schema.columns.table_schema == self.db_schema) - ) - .run(pluck=True) + information_schema = frappe.qb.Schema("information_schema") + + columns = ( + frappe.qb.from_(information_schema.columns) + .select(information_schema.columns.column_name) + .where( + (information_schema.columns.table_name == table) + & (information_schema.columns.table_schema == self.db_schema) ) + .run(pluck=True) + ) - if columns: - frappe.cache.hset("table_columns", table, columns) + frappe.cache.hset("table_columns", table, columns) return columns From c299c01503f3949a100ae5f89d41d4e00bdcc257 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 22 Jul 2024 12:55:56 +0530 Subject: [PATCH 115/176] feat: allow disabling background print for a smaller number of documents - Saves some storage as the PDFs aren't created as files - Some sites are facing issues with background print, this can still be used while that's investigated Signed-off-by: Akhil Narang --- .../public/js/frappe/list/bulk_operations.js | 80 +++++++++++++------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index 464c90a8e8..1c045bc6ae 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -11,6 +11,7 @@ export default class BulkOperations { const allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled); const letterheads = this.get_letterhead_options(); const MAX_PRINT_LIMIT = 500; + const BACKGROUND_PRINT_THRESHOLD = 25; const valid_docs = docs .filter((doc) => { @@ -81,6 +82,13 @@ export default class BulkOperations { depends_on: 'eval:doc.page_size == "Custom"', default: print_settings.pdf_page_width, }, + { + fieldtype: "Check", + label: __("Background Print (required for >25 documents)"), + fieldname: "background_print", + default: valid_docs.length > BACKGROUND_PRINT_THRESHOLD, + read_only: valid_docs.length > BACKGROUND_PRINT_THRESHOLD, + }, ], }); @@ -105,33 +113,55 @@ export default class BulkOperations { pdf_options = JSON.stringify({ "page-size": args.page_size }); } - frappe - .call("frappe.utils.print_format.download_multi_pdf_async", { - doctype: this.doctype, - name: json_string, - format: print_format, - no_letterhead: with_letterhead ? "0" : "1", - letterhead: letterhead, - options: pdf_options, - }) - .then((response) => { - let task_id = response.message.task_id; - frappe.realtime.task_subscribe(task_id); - frappe.realtime.on(`task_complete:${task_id}`, (data) => { - frappe.msgprint({ - title: __("Bulk PDF Export"), - message: __("Your PDF is ready for download"), - primary_action: { - label: __("Download PDF"), - client_action: "window.open", - args: data.file_url, - }, + if (args.background_print) { + frappe + .call("frappe.utils.print_format.download_multi_pdf_async", { + doctype: this.doctype, + name: json_string, + format: print_format, + no_letterhead: with_letterhead ? "0" : "1", + letterhead: letterhead, + options: pdf_options, + }) + .then((response) => { + let task_id = response.message.task_id; + frappe.realtime.task_subscribe(task_id); + frappe.realtime.on(`task_complete:${task_id}`, (data) => { + frappe.msgprint({ + title: __("Bulk PDF Export"), + message: __("Your PDF is ready for download"), + primary_action: { + label: __("Download PDF"), + client_action: "window.open", + args: data.file_url, + }, + }); + frappe.realtime.task_unsubscribe(task_id); + frappe.realtime.off(`task_complete:${task_id}`); }); - frappe.realtime.task_unsubscribe(task_id); - frappe.realtime.off(`task_complete:${task_id}`); }); - dialog.hide(); - }); + } else { + const w = window.open( + "/api/method/frappe.utils.print_format.download_multi_pdf?" + + "doctype=" + + encodeURIComponent(this.doctype) + + "&name=" + + encodeURIComponent(json_string) + + "&format=" + + encodeURIComponent(print_format) + + "&no_letterhead=" + + (with_letterhead ? "0" : "1") + + "&letterhead=" + + encodeURIComponent(letterhead) + + "&options=" + + encodeURIComponent(pdf_options) + ); + + if (!w) { + frappe.msgprint(__("Please enable pop-ups")); + } + } + dialog.hide(); }); dialog.show(); } From f9c7d8c386d691234b3563bf4584eda66d086536 Mon Sep 17 00:00:00 2001 From: Maxim Sysoev Date: Mon, 22 Jul 2024 11:36:36 +0300 Subject: [PATCH 116/176] feat: Chart labels from title_field if use Group by Type (#27173) * feat: Chart labels from title_field if use Group by Type * formatting * Formatting * trim trailing whitespace * trim trailing whitespace --- frappe/desk/doctype/dashboard_chart/dashboard_chart.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index a425da5980..65836b2b2f 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -279,6 +279,16 @@ def get_group_by_chart_config(chart, filters) -> dict | None: ignore_ifnull=True, ) + group_by_field_field = frappe.get_meta(doctype).get_field( + group_by_field + ) # get info about @group_by_field + + if data and group_by_field_field.fieldtype == "Link": # if @group_by_field is link + title_field = frappe.get_meta(group_by_field_field.options) # get title field + if title_field.title_field: # if has title_field + for item in data: # replace chart labels from name to title value + item.name = frappe.get_value(group_by_field_field.options, item.name, title_field.title_field) + if data: return { "labels": [item.get("name", "Not Specified") for item in data], From 427fd6f420a8e73099d801b1ea81fb69399f8677 Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Mon, 22 Jul 2024 16:23:16 +0530 Subject: [PATCH 117/176] fix: calculation according to the decimal digit (#26510) * fix: calculation according to the decimal digit * fix: calculation according to the decimal digit * fix: calculation according to the decimal digit * fix: calculation according to the decimal digit * fix: calculation according to the decimal digit --- .../js/frappe/ui/toolbar/awesome_bar.js | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/ui/toolbar/awesome_bar.js b/frappe/public/js/frappe/ui/toolbar/awesome_bar.js index 7ef9e19383..fd4f121e57 100644 --- a/frappe/public/js/frappe/ui/toolbar/awesome_bar.js +++ b/frappe/public/js/frappe/ui/toolbar/awesome_bar.js @@ -338,6 +338,11 @@ frappe.search.AwesomeBar = class AwesomeBar { } make_calculator(txt) { + function getDecimalPlaces(num) { + if (Math.floor(num) === num) return 0; + return num.toString().split(".")[1].length || 0; + } + var first = txt.substr(0, 1); if (first == parseInt(first) || first === "(" || first === "=") { if (first === "=") { @@ -345,11 +350,29 @@ frappe.search.AwesomeBar = class AwesomeBar { } try { var val = eval(txt); - var formatted_value = __("{0} = {1}", [txt, (val + "").bold()]); + + // Split the input to find the numbers and their decimal places + var numbers = txt.match(/[+-]?([0-9]*[.])?[0-9]+/g); + var maxDecimalPlaces = 0; + if (numbers) { + maxDecimalPlaces = Math.max( + ...numbers.map((num) => getDecimalPlaces(parseFloat(num))) + ); + } + + // Use a default precision of 2 decimal places if no decimal places are found + if (maxDecimalPlaces === 0) { + maxDecimalPlaces = 2; + } + + // Adjust the result to the maximum number of decimal places found or default precision + var rounded_val = parseFloat(val.toFixed(maxDecimalPlaces)); + + var formatted_value = __("{0} = {1}", [txt, (rounded_val + "").bold()]); this.options.push({ label: formatted_value, - value: __("{0} = {1}", [txt, val]), - match: val, + value: __("{0} = {1}", [txt, rounded_val]), + match: rounded_val, index: 80, default: "Calculator", onclick: function () { From dde466be3d8e78d0ca3ea4de1f8da4899a60b4d3 Mon Sep 17 00:00:00 2001 From: "ALB.Leach" Date: Mon, 22 Jul 2024 12:17:18 +0100 Subject: [PATCH 118/176] feat: Implement OAuth Backend App Flow for Email Accounts (#27167) * feat: Implement OAuth Backend App Flow for Email Accounts * chore: Reformat to satisfy linter * chore: format Signed-off-by: Akhil Narang --------- Signed-off-by: Akhil Narang Co-authored-by: Akhil Narang --- .../doctype/email_account/email_account.js | 6 ++++- .../doctype/email_account/email_account.json | 18 ++++++++++---- .../doctype/email_account/email_account.py | 14 ++++++++--- .../doctype/connected_app/connected_app.py | 24 +++++++++++++++++++ 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.js b/frappe/email/doctype/email_account/email_account.js index 3a0baa9564..c0632f7ad5 100644 --- a/frappe/email/doctype/email_account/email_account.js +++ b/frappe/email/doctype/email_account/email_account.js @@ -199,7 +199,11 @@ frappe.ui.form.on("Email Account", { }, show_oauth_authorization_message(frm) { - if (frm.doc.auth_method === "OAuth" && frm.doc.connected_app) { + if ( + frm.doc.auth_method === "OAuth" && + frm.doc.connected_app && + !frm.doc.backend_app_flow + ) { frappe.call({ method: "frappe.integrations.doctype.connected_app.connected_app.has_token", args: { diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index dd244285c1..cca7cc7165 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -18,6 +18,7 @@ "frappe_mail_site", "authentication_column", "auth_method", + "backend_app_flow", "authorize_api_access", "validate_frappe_mail_settings", "password", @@ -99,7 +100,7 @@ }, { "default": "0", - "depends_on": "eval: doc.service != \"Frappe Mail\"", + "depends_on": "eval: doc.service != \"Frappe Mail\" && !doc.backend_app_flow", "fieldname": "login_id_is_different", "fieldtype": "Check", "hide_days": 1, @@ -581,7 +582,7 @@ "label": "IMAP Details" }, { - "depends_on": "eval: doc.auth_method === \"OAuth\" && doc.connected_app && doc.connected_user", + "depends_on": "eval: doc.auth_method === \"OAuth\" && doc.connected_app && doc.connected_user && !doc.backend_app_flow", "fieldname": "authorize_api_access", "fieldtype": "Button", "label": "Authorize API Access" @@ -610,11 +611,11 @@ "options": "Connected App" }, { - "depends_on": "eval: doc.auth_method === \"OAuth\"", + "depends_on": "eval: doc.auth_method === \"OAuth\" && !doc.backend_app_flow", "fieldname": "connected_user", "fieldtype": "Link", "label": "Connected User", - "mandatory_depends_on": "eval: doc.auth_method === \"OAuth\"", + "mandatory_depends_on": "eval: doc.auth_method === \"OAuth\" && !doc.backend_app_flow", "options": "User" }, { @@ -684,12 +685,19 @@ "fieldtype": "Password", "label": "API Secret", "mandatory_depends_on": "eval: doc.service == \"Frappe Mail\" && doc.auth_method == \"Basic\"" + }, + { + "default": "0", + "depends_on": "eval: doc.auth_method === \"OAuth\"", + "fieldname": "backend_app_flow", + "fieldtype": "Check", + "label": "Authenticate as Service Principal" } ], "icon": "fa fa-inbox", "index_web_pages_for_search": 1, "links": [], - "modified": "2024-06-28 08:45:43.565934", + "modified": "2024-07-18 11:05:57.193762", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index aac4a97587..cee8b21e3f 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -71,6 +71,7 @@ class EmailAccount(Document): auth_method: DF.Literal["Basic", "OAuth"] auto_reply_message: DF.TextEditor | None awaiting_password: DF.Check + backend_app_flow: DF.Check brand_logo: DF.AttachImage | None connected_app: DF.Link | None connected_user: DF.Link | None @@ -780,7 +781,12 @@ class EmailAccount(Document): def get_oauth_token(self): if self.auth_method == "OAuth": connected_app = frappe.get_doc("Connected App", self.connected_app) - return connected_app.get_active_token(self.connected_user) + if self.backend_app_flow: + token = connected_app.get_backend_app_token() + else: + token = connected_app.get_active_token(self.connected_user) + + return token @frappe.whitelist() @@ -879,8 +885,10 @@ def pull(now=False): ) for email_account in email_accounts: - if email_account.auth_method == "OAuth" and not has_token( - email_account.connected_app, email_account.connected_user + if ( + email_account.auth_method == "OAuth" + and not email_account.backend_app_flow + and not has_token(email_account.connected_app, email_account.connected_user) ): # don't try to pull from accounts which dont have access token (for Oauth) continue diff --git a/frappe/integrations/doctype/connected_app/connected_app.py b/frappe/integrations/doctype/connected_app/connected_app.py index 07f5c10b01..0a98869aab 100644 --- a/frappe/integrations/doctype/connected_app/connected_app.py +++ b/frappe/integrations/doctype/connected_app/connected_app.py @@ -4,6 +4,7 @@ import os from urllib.parse import urlencode, urljoin +from oauthlib.oauth2 import BackendApplicationClient from requests_oauthlib import OAuth2Session import frappe @@ -147,6 +148,29 @@ class ConnectedApp(Document): return token_cache + def get_backend_app_token(self): + """Get an Access Token for the Cloud-Registered Service Principal""" + # There is no User assigned to the app, so we give it an empty string, + # otherwise it will assign the logged in user. + token_cache = self.get_token_cache("") + if token_cache is None: + token_cache = frappe.new_doc("Token Cache") + token_cache.connected_app = self.name + elif not token_cache.is_expired(): + return token_cache + + # Get a new Access token for the App + client = BackendApplicationClient(client_id=self.client_id, scope=self.get_scopes()) + oauth_session = OAuth2Session(client=client) + + token = oauth_session.fetch_token(self.token_uri, client_secret=self.get_password("client_secret")) + + token_cache.update_data(token) + token_cache.save(ignore_permissions=True) + frappe.db.commit() + + return token_cache + @frappe.whitelist(methods=["GET"], allow_guest=True) def callback(code=None, state=None): From 82979379f1aa0f7503ca6e4251956534ad00805b Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 22 Jul 2024 18:00:09 +0530 Subject: [PATCH 119/176] chore: update POT file (#27177) --- frappe/locale/main.pot | 371 ++++++++++++++++++++++------------------- 1 file changed, 202 insertions(+), 169 deletions(-) diff --git a/frappe/locale/main.pot b/frappe/locale/main.pot index a9fbc81610..1ba70391ab 100644 --- a/frappe/locale/main.pot +++ b/frappe/locale/main.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Frappe Framework VERSION\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-07-14 09:33+0000\n" -"PO-Revision-Date: 2024-07-14 09:33+0000\n" +"POT-Creation-Date: 2024-07-21 09:33+0000\n" +"PO-Revision-Date: 2024-07-21 09:33+0000\n" "Last-Translator: developers@frappe.io\n" "Language-Team: developers@frappe.io\n" "MIME-Version: 1.0\n" @@ -42,7 +42,7 @@ msgstr "" msgid "\"Team Members\" or \"Management\"" msgstr "" -#: public/js/frappe/form/form.js:1085 +#: public/js/frappe/form/form.js:1089 msgid "\"amended_from\" field must be present to do an amendment." msgstr "" @@ -499,7 +499,7 @@ msgid "" "" msgstr "" -#: twofactor.py:462 +#: twofactor.py:446 msgid "

    Your OTP secret on {0} has been reset. If you did not perform this reset and did not request it, please contact your System Administrator immediately.

    " msgstr "" @@ -958,7 +958,7 @@ msgstr "" #. Group in User's connections #: core/doctype/user/user.json public/js/frappe/form/dashboard.js:22 -#: public/js/frappe/form/footer/form_timeline.js:58 +#: public/js/frappe/form/footer/form_timeline.js:60 msgid "Activity" msgstr "" @@ -1102,7 +1102,7 @@ msgstr "" msgid "Add Review" msgstr "" -#: core/doctype/user/user.py:765 +#: core/doctype/user/user.py:772 msgid "Add Roles" msgstr "" @@ -1135,7 +1135,7 @@ msgstr "" msgid "Add Tags" msgstr "" -#: public/js/frappe/list/list_view.js:1955 +#: public/js/frappe/list/list_view.js:1957 msgctxt "Button in list view actions menu" msgid "Add Tags" msgstr "" @@ -1221,7 +1221,7 @@ msgstr "" msgid "Add to table" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:97 +#: public/js/frappe/form/footer/form_timeline.js:99 msgid "Add to this activity by mailing to {0}" msgstr "" @@ -1257,8 +1257,11 @@ msgstr "" #. DocPerm' #. Label of the additional_permissions (Section Break) field in DocType #. 'DocPerm' +#. Label of the additional_permissions_section (Section Break) field in DocType +#. 'User Document Type' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json +#: core/doctype/user_document_type/user_document_type.json msgid "Additional Permissions" msgstr "" @@ -1353,11 +1356,11 @@ msgstr "" msgid "Administrator" msgstr "" -#: core/doctype/user/user.py:1169 +#: core/doctype/user/user.py:1176 msgid "Administrator Logged In" msgstr "" -#: core/doctype/user/user.py:1163 +#: core/doctype/user/user.py:1170 msgid "Administrator accessed {0} on {1} via IP Address {2}." msgstr "" @@ -1513,7 +1516,7 @@ msgstr "" msgid "All Records" msgstr "" -#: public/js/frappe/form/form.js:2225 +#: public/js/frappe/form/form.js:2230 msgid "All Submissions" msgstr "" @@ -1831,11 +1834,11 @@ msgstr "" msgid "Allowed Roles" msgstr "" -#: public/js/frappe/form/form.js:1251 +#: public/js/frappe/form/form.js:1255 msgid "Allowing DocType, DocType. Be careful!" msgstr "" -#: core/doctype/user/user.py:972 +#: core/doctype/user/user.py:979 msgid "Already Registered" msgstr "" @@ -2047,7 +2050,7 @@ msgstr "" msgid "App Secret Key" msgstr "" -#: modules/utils.py:275 +#: modules/utils.py:279 msgid "App not found for module: {0}" msgstr "" @@ -2112,7 +2115,7 @@ msgstr "" msgid "Applied On" msgstr "" -#: public/js/frappe/list/list_view.js:1940 +#: public/js/frappe/list/list_view.js:1942 msgctxt "Button in list view actions menu" msgid "Apply Assignment Rule" msgstr "" @@ -2206,7 +2209,7 @@ msgstr "" msgid "Archived Columns" msgstr "" -#: public/js/frappe/list/list_view.js:1919 +#: public/js/frappe/list/list_view.js:1921 msgid "Are you sure you want to clear the assignments?" msgstr "" @@ -2302,7 +2305,7 @@ msgstr "" msgid "Assign To" msgstr "" -#: public/js/frappe/list/list_view.js:1901 +#: public/js/frappe/list/list_view.js:1903 msgctxt "Button in list view actions menu" msgid "Assign To" msgstr "" @@ -2421,7 +2424,7 @@ msgstr "" msgid "Assignment Rules" msgstr "" -#: desk/doctype/notification_log/notification_log.py:157 +#: desk/doctype/notification_log/notification_log.py:158 msgid "Assignment Update on {0}" msgstr "" @@ -2831,11 +2834,11 @@ msgstr "" msgid "Automatic" msgstr "" -#: email/doctype/email_account/email_account.py:761 +#: email/doctype/email_account/email_account.py:766 msgid "Automatic Linking can be activated only for one Email Account." msgstr "" -#: email/doctype/email_account/email_account.py:755 +#: email/doctype/email_account/email_account.py:760 msgid "Automatic Linking can be activated only if Incoming is enabled." msgstr "" @@ -3874,7 +3877,7 @@ msgstr "" msgid "Cancel" msgstr "" -#: public/js/frappe/list/list_view.js:2010 +#: public/js/frappe/list/list_view.js:2012 msgctxt "Button in list view actions menu" msgid "Cancel" msgstr "" @@ -3884,11 +3887,11 @@ msgctxt "Secondary button in warning dialog" msgid "Cancel" msgstr "" -#: public/js/frappe/form/form.js:974 +#: public/js/frappe/form/form.js:978 msgid "Cancel All" msgstr "" -#: public/js/frappe/form/form.js:961 +#: public/js/frappe/form/form.js:965 msgid "Cancel All Documents" msgstr "" @@ -3896,7 +3899,7 @@ msgstr "" msgid "Cancel Scheduling" msgstr "" -#: public/js/frappe/list/list_view.js:2015 +#: public/js/frappe/list/list_view.js:2017 msgctxt "Title of confirmation dialog" msgid "Cancel {0} documents?" msgstr "" @@ -4459,7 +4462,7 @@ msgstr "" msgid "Clear & Add template" msgstr "" -#: public/js/frappe/list/list_view.js:1916 +#: public/js/frappe/list/list_view.js:1918 msgctxt "Button in list view actions menu" msgid "Clear Assignment" msgstr "" @@ -4558,7 +4561,7 @@ msgstr "" msgid "Click to Set Filters" msgstr "" -#: public/js/frappe/list/list_view.js:677 +#: public/js/frappe/list/list_view.js:679 msgid "Click to sort by {0}" msgstr "" @@ -4996,7 +4999,7 @@ msgstr "" msgid "Complete By" msgstr "" -#: core/doctype/user/user.py:425 templates/emails/new_user.html:10 +#: core/doctype/user/user.py:432 templates/emails/new_user.html:10 msgid "Complete Registration" msgstr "" @@ -5659,7 +5662,7 @@ msgid "Created Custom Field {0} in {1}" msgstr "" #: desk/doctype/dashboard_chart/dashboard_chart.js:241 -#: email/doctype/notification/notification.js:32 model/meta.py:46 +#: email/doctype/notification/notification.js:33 model/meta.py:46 #: public/js/frappe/model/meta.js:198 public/js/frappe/model/model.js:125 #: public/js/frappe/views/dashboard/dashboard_view.js:478 msgid "Created On" @@ -6018,7 +6021,7 @@ msgstr "" msgid "Customizations Reset" msgstr "" -#: modules/utils.py:91 +#: modules/utils.py:95 msgid "Customizations for {0} exported to:
    {1}" msgstr "" @@ -6029,7 +6032,7 @@ msgstr "" msgid "Customize" msgstr "" -#: public/js/frappe/list/list_view.js:1761 +#: public/js/frappe/list/list_view.js:1763 msgctxt "Button in list view menu" msgid "Customize" msgstr "" @@ -6675,7 +6678,7 @@ msgstr "" #: core/doctype/docperm/docperm.json #: core/doctype/user_document_type/user_document_type.json #: core/doctype/user_permission/user_permission_list.js:189 -#: public/js/frappe/form/footer/form_timeline.js:613 +#: public/js/frappe/form/footer/form_timeline.js:615 #: public/js/frappe/form/grid.js:63 public/js/frappe/form/toolbar.js:434 #: public/js/frappe/views/reports/report_view.js:1654 #: public/js/frappe/views/treeview.js:308 @@ -6685,7 +6688,7 @@ msgstr "" msgid "Delete" msgstr "" -#: public/js/frappe/list/list_view.js:1978 +#: public/js/frappe/list/list_view.js:1980 msgctxt "Button in list view actions menu" msgid "Delete" msgstr "" @@ -6714,7 +6717,7 @@ msgstr "" msgid "Delete and Generate New" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:719 +#: public/js/frappe/form/footer/form_timeline.js:721 msgid "Delete comment?" msgstr "" @@ -6722,12 +6725,12 @@ msgstr "" msgid "Delete this record to allow sending to this email address" msgstr "" -#: public/js/frappe/list/list_view.js:1983 +#: public/js/frappe/list/list_view.js:1985 msgctxt "Title of confirmation dialog" msgid "Delete {0} item permanently?" msgstr "" -#: public/js/frappe/list/list_view.js:1989 +#: public/js/frappe/list/list_view.js:1991 msgctxt "Title of confirmation dialog" msgid "Delete {0} items permanently?" msgstr "" @@ -6966,7 +6969,7 @@ msgstr "" #: desk/doctype/event/event.json #: desk/page/user_profile/user_profile_sidebar.html:45 #: public/js/form_builder/store.js:259 public/js/form_builder/utils.js:38 -#: public/js/frappe/form/layout.js:135 public/js/frappe/views/treeview.js:271 +#: public/js/frappe/form/layout.js:137 public/js/frappe/views/treeview.js:271 msgid "Details" msgstr "" @@ -7131,7 +7134,7 @@ msgctxt "Button in web form" msgid "Discard" msgstr "" -#: public/js/frappe/form/form.js:840 +#: public/js/frappe/form/form.js:844 msgid "Discard {0}" msgstr "" @@ -7158,7 +7161,7 @@ msgstr "" msgid "Discussion Topic" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:623 +#: public/js/frappe/form/footer/form_timeline.js:625 #: templates/discussions/reply_card.html:16 #: templates/discussions/reply_section.html:29 msgid "Dismiss" @@ -7209,7 +7212,7 @@ msgstr "" msgid "Do you still want to proceed?" msgstr "" -#: public/js/frappe/form/form.js:953 +#: public/js/frappe/form/form.js:957 msgid "Do you want to cancel all linked documents?" msgstr "" @@ -7385,11 +7388,11 @@ msgstr "" msgid "DocType required" msgstr "" -#: modules/utils.py:170 +#: modules/utils.py:174 msgid "DocType {0} does not exist." msgstr "" -#: modules/utils.py:233 +#: modules/utils.py:237 msgid "DocType {} not found" msgstr "" @@ -7679,15 +7682,15 @@ msgstr "" msgid "Document Unlocked" msgstr "" -#: public/js/frappe/list/list_view.js:1116 +#: public/js/frappe/list/list_view.js:1118 msgid "Document has been cancelled" msgstr "" -#: public/js/frappe/list/list_view.js:1115 +#: public/js/frappe/list/list_view.js:1117 msgid "Document has been submitted" msgstr "" -#: public/js/frappe/list/list_view.js:1114 +#: public/js/frappe/list/list_view.js:1116 msgid "Document is in draft state" msgstr "" @@ -8049,8 +8052,8 @@ msgstr "" #: printing/page/print_format_builder_beta/print_format_builder_beta.js:46 #: printing/page/print_format_builder_beta/print_format_builder_beta.js:85 #: public/js/frappe/form/controls/markdown_editor.js:31 -#: public/js/frappe/form/footer/form_timeline.js:652 -#: public/js/frappe/form/footer/form_timeline.js:661 +#: public/js/frappe/form/footer/form_timeline.js:654 +#: public/js/frappe/form/footer/form_timeline.js:663 #: public/js/frappe/form/templates/address_list.html:7 #: public/js/frappe/form/templates/contact_list.html:7 #: public/js/frappe/form/toolbar.js:681 @@ -8068,7 +8071,7 @@ msgstr "" msgid "Edit" msgstr "" -#: public/js/frappe/list/list_view.js:2064 +#: public/js/frappe/list/list_view.js:2066 msgctxt "Button in list view actions menu" msgid "Edit" msgstr "" @@ -8098,7 +8101,7 @@ msgstr "" msgid "Edit DocType" msgstr "" -#: public/js/frappe/list/list_view.js:1788 +#: public/js/frappe/list/list_view.js:1790 msgctxt "Button in list view menu" msgid "Edit DocType" msgstr "" @@ -8244,6 +8247,7 @@ msgstr "" #. Label of the email_tab (Tab Break) field in DocType 'System Settings' #. Label of the email (Data) field in DocType 'User' #. Label of the email_settings (Section Break) field in DocType 'User' +#. Label of the email (Check) field in DocType 'User Document Type' #. Label of the email (Data) field in DocType 'Event Participants' #. Label of the email (Data) field in DocType 'Email Group Member' #. Label of the email (Data) field in DocType 'Email Unsubscribe' @@ -8256,6 +8260,7 @@ msgstr "" #: core/doctype/success_action/success_action.js:57 #: core/doctype/system_settings/system_settings.json #: core/doctype/user/user.json +#: core/doctype/user_document_type/user_document_type.json #: desk/doctype/event_participants/event_participants.json #: email/doctype/email_group_member/email_group_member.json #: email/doctype/email_unsubscribe/email_unsubscribe.json @@ -8300,7 +8305,7 @@ msgstr "" msgid "Email Account Name" msgstr "" -#: core/doctype/user/user.py:698 +#: core/doctype/user/user.py:705 msgid "Email Account added multiple times" msgstr "" @@ -8680,7 +8685,7 @@ msgstr "" #. Label of the enable_two_factor_auth (Check) field in DocType 'System #. Settings' -#: core/doctype/system_settings/system_settings.json twofactor.py:449 +#: core/doctype/system_settings/system_settings.json twofactor.py:433 msgid "Enable Two Factor Auth" msgstr "" @@ -8750,7 +8755,7 @@ msgstr "" msgid "Enabled Scheduler" msgstr "" -#: email/doctype/email_account/email_account.py:982 +#: email/doctype/email_account/email_account.py:987 msgid "Enabled email inbox for user {0}" msgstr "" @@ -8861,7 +8866,7 @@ msgstr "" msgid "Energy Point Settings" msgstr "" -#: desk/doctype/notification_log/notification_log.py:159 +#: desk/doctype/notification_log/notification_log.py:160 msgid "Energy Point Update on {0}" msgstr "" @@ -9035,9 +9040,9 @@ msgstr "" msgid "Error in Header/Footer Script" msgstr "" -#: email/doctype/notification/notification.py:399 -#: email/doctype/notification/notification.py:515 -#: email/doctype/notification/notification.py:521 +#: email/doctype/notification/notification.py:443 +#: email/doctype/notification/notification.py:559 +#: email/doctype/notification/notification.py:565 msgid "Error in Notification" msgstr "" @@ -9045,11 +9050,11 @@ msgstr "" msgid "Error in print format on line {0}: {1}" msgstr "" -#: email/doctype/email_account/email_account.py:659 +#: email/doctype/email_account/email_account.py:664 msgid "Error while connecting to email account {0}" msgstr "" -#: email/doctype/notification/notification.py:512 +#: email/doctype/notification/notification.py:556 msgid "Error while evaluating Notification {0}. Please fix your template." msgstr "" @@ -9287,7 +9292,7 @@ msgstr "" msgid "Export" msgstr "" -#: public/js/frappe/list/list_view.js:2086 +#: public/js/frappe/list/list_view.js:2088 msgctxt "Button in list view actions menu" msgid "Export" msgstr "" @@ -9698,10 +9703,14 @@ msgstr "" msgid "Field {0} is referring to non-existing doctype {1}." msgstr "" -#: public/js/frappe/form/form.js:1761 +#: public/js/frappe/form/form.js:1765 msgid "Field {0} not found." msgstr "" +#: email/doctype/notification/notification.py:348 +msgid "Field {0} on document {1} is neither a Mobile number field nor a Customer or User link" +msgstr "" + #. Label of the fieldname (Data) field in DocType 'Report Column' #. Label of the fieldname (Data) field in DocType 'Report Filter' #. Label of the fieldname (Data) field in DocType 'Custom Field' @@ -9834,7 +9843,7 @@ msgctxt "File" msgid "File" msgstr "" -#: core/doctype/file/utils.py:127 +#: core/doctype/file/utils.py:128 msgid "File '{0}' not found" msgstr "" @@ -10778,7 +10787,7 @@ msgstr "" msgid "Geolocation" msgstr "" -#: email/doctype/notification/notification.js:175 +#: email/doctype/notification/notification.js:193 msgid "Get Alerts for Today" msgstr "" @@ -11603,7 +11612,7 @@ msgstr "" msgid "Hide Standard Menu" msgstr "" -#: public/js/frappe/list/list_view.js:1663 +#: public/js/frappe/list/list_view.js:1665 msgid "Hide Tags" msgstr "" @@ -11621,7 +11630,7 @@ msgstr "" msgid "Hide descendant records of For Value." msgstr "" -#: public/js/frappe/form/layout.js:268 +#: public/js/frappe/form/layout.js:270 msgid "Hide details" msgstr "" @@ -12122,7 +12131,7 @@ msgstr "" msgid "Image field must be of type Attach Image" msgstr "" -#: core/doctype/file/utils.py:135 +#: core/doctype/file/utils.py:136 msgid "Image link '{0}' is not valid" msgstr "" @@ -12130,6 +12139,10 @@ msgstr "" msgid "Image optimized" msgstr "" +#: core/doctype/file/utils.py:283 +msgid "Image: Corrupted Data Stream" +msgstr "" + #: public/js/frappe/views/image/image_view.js:13 msgid "Images" msgstr "" @@ -12168,7 +12181,7 @@ msgstr "" msgid "Import" msgstr "" -#: public/js/frappe/list/list_view.js:1725 +#: public/js/frappe/list/list_view.js:1727 msgctxt "Button in list view menu" msgid "Import" msgstr "" @@ -12757,7 +12770,7 @@ msgid "Invalid" msgstr "" #: public/js/form_builder/utils.js:221 public/js/frappe/form/grid_row.js:770 -#: public/js/frappe/form/layout.js:793 +#: public/js/frappe/form/layout.js:795 msgid "Invalid \"depends_on\" expression" msgstr "" @@ -12861,7 +12874,7 @@ msgstr "" msgid "Invalid Parameters." msgstr "" -#: core/doctype/user/user.py:1184 www/update-password.html:121 +#: core/doctype/user/user.py:1191 www/update-password.html:121 #: www/update-password.html:142 www/update-password.html:144 #: www/update-password.html:245 msgid "Invalid Password" @@ -13230,7 +13243,7 @@ msgstr "" msgid "Is Virtual" msgstr "" -#: core/doctype/file/utils.py:156 utils/file_manager.py:311 +#: core/doctype/file/utils.py:157 utils/file_manager.py:311 msgid "It is risky to delete this file: {0}. Please contact your System Manager." msgstr "" @@ -13737,7 +13750,7 @@ msgstr "" msgid "Last Login" msgstr "" -#: email/doctype/notification/notification.js:33 +#: email/doctype/notification/notification.js:34 msgid "Last Modified Date" msgstr "" @@ -13872,7 +13885,7 @@ msgid "Leave blank to repeat always" msgstr "" #: core/doctype/communication/mixins.py:207 -#: email/doctype/email_account/email_account.py:709 +#: email/doctype/email_account/email_account.py:714 msgid "Leave this conversation" msgstr "" @@ -14317,7 +14330,7 @@ msgstr "" msgid "List Settings" msgstr "" -#: public/js/frappe/list/list_view.js:1805 +#: public/js/frappe/list/list_view.js:1807 msgctxt "Button in list view menu" msgid "List Settings" msgstr "" @@ -14368,7 +14381,7 @@ msgstr "" msgid "Load More" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:214 +#: public/js/frappe/form/footer/form_timeline.js:216 msgctxt "Form timeline" msgid "Load More Communications" msgstr "" @@ -15408,7 +15421,7 @@ msgstr "" msgid "Module to Export" msgstr "" -#: modules/utils.py:268 +#: modules/utils.py:272 msgid "Module {} not found" msgstr "" @@ -15778,12 +15791,12 @@ msgstr "" msgid "Navigate Home" msgstr "" -#: public/js/frappe/list/list_view.js:1196 +#: public/js/frappe/list/list_view.js:1198 msgctxt "Description of a list view shortcut" msgid "Navigate list down" msgstr "" -#: public/js/frappe/list/list_view.js:1203 +#: public/js/frappe/list/list_view.js:1205 msgctxt "Description of a list view shortcut" msgid "Navigate list up" msgstr "" @@ -15867,11 +15880,11 @@ msgstr "" msgid "New Document Form" msgstr "" -#: desk/doctype/notification_log/notification_log.py:158 +#: desk/doctype/notification_log/notification_log.py:159 msgid "New Document Shared {0}" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:26 +#: public/js/frappe/form/footer/form_timeline.js:27 #: public/js/frappe/views/communication.js:23 msgid "New Email" msgstr "" @@ -15881,7 +15894,7 @@ msgstr "" msgid "New Email Account" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:45 +#: public/js/frappe/form/footer/form_timeline.js:47 msgid "New Event" msgstr "" @@ -15897,7 +15910,7 @@ msgstr "" msgid "New Links" msgstr "" -#: desk/doctype/notification_log/notification_log.py:156 +#: desk/doctype/notification_log/notification_log.py:157 msgid "New Mention on {0}" msgstr "" @@ -15915,7 +15928,7 @@ msgstr "" msgid "New Newsletter" msgstr "" -#: desk/doctype/notification_log/notification_log.py:155 +#: desk/doctype/notification_log/notification_log.py:156 msgid "New Notification" msgstr "" @@ -16020,7 +16033,7 @@ msgstr "" msgid "New {} releases for the following apps are available" msgstr "" -#: core/doctype/user/user.py:761 +#: core/doctype/user/user.py:768 msgid "Newly created user {0} has no roles enabled." msgstr "" @@ -16299,7 +16312,7 @@ msgstr "" msgid "No Results found" msgstr "" -#: core/doctype/user/user.py:762 +#: core/doctype/user/user.py:769 msgid "No Roles Specified" msgstr "" @@ -16327,7 +16340,7 @@ msgstr "" msgid "No address added yet." msgstr "" -#: email/doctype/notification/notification.js:185 +#: email/doctype/notification/notification.js:203 msgid "No alerts for today" msgstr "" @@ -16458,7 +16471,7 @@ msgstr "" msgid "No permission for {0}" msgstr "" -#: public/js/frappe/form/form.js:1137 +#: public/js/frappe/form/form.js:1141 msgctxt "{0} = verb, {1} = object" msgid "No permission to '{0}' {1}" msgstr "" @@ -16549,7 +16562,7 @@ msgstr "" msgid "Normalized Query" msgstr "" -#: core/doctype/user/user.py:967 templates/includes/login/login.js:257 +#: core/doctype/user/user.py:974 templates/includes/login/login.js:257 #: utils/oauth.py:265 msgid "Not Allowed" msgstr "" @@ -16648,7 +16661,7 @@ msgstr "" msgid "Not a valid Comma Separated Value (CSV File)" msgstr "" -#: core/doctype/user/user.py:234 +#: core/doctype/user/user.py:240 msgid "Not a valid User Image." msgstr "" @@ -16668,7 +16681,7 @@ msgstr "" msgid "Not allowed for {0}: {1}" msgstr "" -#: email/doctype/notification/notification.py:396 +#: email/doctype/notification/notification.py:440 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "" @@ -16850,6 +16863,18 @@ msgstr "" msgid "Notification sent to" msgstr "" +#: email/doctype/notification/notification.py:345 +msgid "Notification: customer {0} has no Mobile number set" +msgstr "" + +#: email/doctype/notification/notification.py:331 +msgid "Notification: document {0} has no {1} number set (field: {2})" +msgstr "" + +#: email/doctype/notification/notification.py:340 +msgid "Notification: user {0} has no Mobile number set" +msgstr "" + #. Label of the notifications (Check) field in DocType 'Role' #: core/doctype/role/role.json #: public/js/frappe/ui/notifications/notifications.js:50 @@ -17078,11 +17103,11 @@ msgstr "" msgid "OTP Issuer Name" msgstr "" -#: twofactor.py:461 +#: twofactor.py:445 msgid "OTP Secret Reset - {0}" msgstr "" -#: twofactor.py:480 +#: twofactor.py:464 msgid "OTP Secret has been reset. Re-registration will be required on next login." msgstr "" @@ -17418,7 +17443,7 @@ msgstr "" msgid "Open a module or tool" msgstr "" -#: public/js/frappe/list/list_view.js:1249 +#: public/js/frappe/list/list_view.js:1251 msgctxt "Description of a list view shortcut" msgid "Open list item" msgstr "" @@ -18011,11 +18036,11 @@ msgstr "" msgid "Password" msgstr "" -#: core/doctype/user/user.py:1030 +#: core/doctype/user/user.py:1037 msgid "Password Email Sent" msgstr "" -#: core/doctype/user/user.py:405 +#: core/doctype/user/user.py:412 msgid "Password Reset" msgstr "" @@ -18049,7 +18074,7 @@ msgstr "" msgid "Password not found for {0} {1} {2}" msgstr "" -#: core/doctype/user/user.py:1029 +#: core/doctype/user/user.py:1036 msgid "Password reset instructions have been sent to {}'s email" msgstr "" @@ -18061,7 +18086,7 @@ msgstr "" msgid "Password size exceeded the maximum allowed size" msgstr "" -#: core/doctype/user/user.py:825 +#: core/doctype/user/user.py:832 msgid "Password size exceeded the maximum allowed size." msgstr "" @@ -18199,15 +18224,15 @@ msgstr "" msgid "Permanent" msgstr "" -#: public/js/frappe/form/form.js:1023 +#: public/js/frappe/form/form.js:1027 msgid "Permanently Cancel {0}?" msgstr "" -#: public/js/frappe/form/form.js:1069 +#: public/js/frappe/form/form.js:1073 msgid "Permanently Discard {0}?" msgstr "" -#: public/js/frappe/form/form.js:853 +#: public/js/frappe/form/form.js:857 msgid "Permanently Submit {0}?" msgstr "" @@ -18426,7 +18451,7 @@ msgstr "" msgid "Please add a valid comment." msgstr "" -#: core/doctype/user/user.py:1012 +#: core/doctype/user/user.py:1019 msgid "Please ask your administrator to verify your sign-up" msgstr "" @@ -18458,7 +18483,7 @@ msgstr "" msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "" -#: core/doctype/user/user.py:1010 +#: core/doctype/user/user.py:1017 msgid "Please check your email for verification" msgstr "" @@ -18744,7 +18769,7 @@ msgstr "" msgid "Please setup default Email Account from Settings > Email Account" msgstr "" -#: core/doctype/user/user.py:370 +#: core/doctype/user/user.py:377 msgid "Please setup default outgoing Email Account from Settings > Email Account" msgstr "" @@ -19047,7 +19072,7 @@ msgstr "" msgid "Previous Hash" msgstr "" -#: public/js/frappe/form/form.js:2217 +#: public/js/frappe/form/form.js:2222 msgid "Previous Submission" msgstr "" @@ -19087,9 +19112,11 @@ msgstr "" #. Label of the print (Check) field in DocType 'Custom DocPerm' #. Label of the print (Check) field in DocType 'DocPerm' +#. Label of the print (Check) field in DocType 'User Document Type' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json #: core/doctype/success_action/success_action.js:56 +#: core/doctype/user_document_type/user_document_type.json #: printing/page/print/print.js:65 public/js/frappe/form/success_action.js:81 #: public/js/frappe/form/templates/print_layout.html:46 #: public/js/frappe/form/toolbar.js:332 public/js/frappe/form/toolbar.js:344 @@ -19100,7 +19127,7 @@ msgstr "" msgid "Print" msgstr "" -#: public/js/frappe/list/list_view.js:1970 +#: public/js/frappe/list/list_view.js:1972 msgctxt "Button in list view actions menu" msgid "Print" msgstr "" @@ -19843,12 +19870,12 @@ msgstr "" msgid "Re-Run in Console" msgstr "" -#: email/doctype/email_account/email_account.py:715 +#: email/doctype/email_account/email_account.py:720 msgid "Re:" msgstr "" #: core/doctype/communication/communication.js:268 -#: public/js/frappe/form/footer/form_timeline.js:587 +#: public/js/frappe/form/footer/form_timeline.js:589 #: public/js/frappe/views/communication.js:355 msgid "Re: {0}" msgstr "" @@ -20311,7 +20338,7 @@ msgid "Referrer" msgstr "" #: printing/page/print/print.js:73 public/js/frappe/desk.js:134 -#: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1196 +#: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1200 #: public/js/frappe/form/templates/print_layout.html:6 #: public/js/frappe/list/base_list.js:66 #: public/js/frappe/views/reports/query_report.js:1629 @@ -20353,7 +20380,7 @@ msgstr "" msgid "Refreshing..." msgstr "" -#: core/doctype/user/user.py:974 +#: core/doctype/user/user.py:981 msgid "Registered but disabled" msgstr "" @@ -20570,7 +20597,7 @@ msgstr "" #. Label of the reply (Text Editor) field in DocType 'Discussion Reply' #: core/doctype/communication/communication.js:57 -#: public/js/frappe/form/footer/form_timeline.js:550 +#: public/js/frappe/form/footer/form_timeline.js:552 #: website/doctype/discussion_reply/discussion_reply.json msgid "Reply" msgstr "" @@ -21244,7 +21271,7 @@ msgstr "" msgid "Role Permissions Manager" msgstr "" -#: public/js/frappe/list/list_view.js:1747 +#: public/js/frappe/list/list_view.js:1749 msgctxt "Button in list view menu" msgid "Role Permissions Manager" msgstr "" @@ -21276,7 +21303,7 @@ msgstr "" msgid "Role and Level" msgstr "" -#: core/doctype/user/user.py:315 +#: core/doctype/user/user.py:322 msgid "Role has been set as per the user type {0}" msgstr "" @@ -21675,7 +21702,7 @@ msgstr "" #: email/doctype/notification/notification.json #: printing/page/print/print.js:856 #: printing/page/print_format_builder/print_format_builder.js:160 -#: public/js/frappe/form/footer/form_timeline.js:661 +#: public/js/frappe/form/footer/form_timeline.js:663 #: public/js/frappe/form/quick_entry.js:161 #: public/js/frappe/list/list_settings.js:36 #: public/js/frappe/list/list_settings.js:244 @@ -22072,7 +22099,7 @@ msgstr "" msgid "See all past reports." msgstr "" -#: public/js/frappe/form/form.js:1230 +#: public/js/frappe/form/form.js:1234 #: website/doctype/contact_us_settings/contact_us_settings.js:4 msgid "See on Website" msgstr "" @@ -22360,13 +22387,13 @@ msgstr "" msgid "Select atleast 2 actions" msgstr "" -#: public/js/frappe/list/list_view.js:1263 +#: public/js/frappe/list/list_view.js:1265 msgctxt "Description of a list view shortcut" msgid "Select list item" msgstr "" -#: public/js/frappe/list/list_view.js:1215 -#: public/js/frappe/list/list_view.js:1231 +#: public/js/frappe/list/list_view.js:1217 +#: public/js/frappe/list/list_view.js:1233 msgctxt "Description of a list view shortcut" msgid "Select multiple list items" msgstr "" @@ -23098,9 +23125,11 @@ msgstr "" #. Label of the share (Check) field in DocType 'Custom DocPerm' #. Label of the share (Check) field in DocType 'DocPerm' #. Label of the share (Check) field in DocType 'DocShare' +#. Label of the share (Check) field in DocType 'User Document Type' #. Option for the 'Type' (Select) field in DocType 'Notification Log' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json core/doctype/docshare/docshare.json +#: core/doctype/user_document_type/user_document_type.json #: desk/doctype/notification_log/notification_log.json #: public/js/frappe/form/templates/form_sidebar.html:110 msgid "Share" @@ -23212,7 +23241,7 @@ msgstr "" msgid "Show Error" msgstr "" -#: public/js/frappe/form/layout.js:561 +#: public/js/frappe/form/layout.js:563 msgid "Show Fieldname (click to copy on clipboard)" msgstr "" @@ -23330,7 +23359,7 @@ msgid "Show Sidebar" msgstr "" #: public/js/frappe/list/list_sidebar.html:66 -#: public/js/frappe/list/list_view.js:1663 +#: public/js/frappe/list/list_view.js:1665 msgid "Show Tags" msgstr "" @@ -23377,7 +23406,7 @@ msgstr "" msgid "Show all Versions" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:67 +#: public/js/frappe/form/footer/form_timeline.js:69 msgid "Show all activity" msgstr "" @@ -23417,7 +23446,7 @@ msgstr "" msgid "Show link to document" msgstr "" -#: public/js/frappe/form/layout.js:255 public/js/frappe/form/layout.js:273 +#: public/js/frappe/form/layout.js:257 public/js/frappe/form/layout.js:275 msgid "Show more details" msgstr "" @@ -23471,7 +23500,7 @@ msgstr "" msgid "Sign Up and Confirmation" msgstr "" -#: core/doctype/user/user.py:967 +#: core/doctype/user/user.py:974 msgid "Sign Up is disabled" msgstr "" @@ -23587,7 +23616,7 @@ msgstr "" msgid "Skipping column {0}" msgstr "" -#: modules/utils.py:171 +#: modules/utils.py:175 msgid "Skipping fixture syncing for doctype {0} from file {1}" msgstr "" @@ -24275,7 +24304,7 @@ msgstr "" msgid "Submit" msgstr "" -#: public/js/frappe/list/list_view.js:2037 +#: public/js/frappe/list/list_view.js:2039 msgctxt "Button in list view actions menu" msgid "Submit" msgstr "" @@ -24328,11 +24357,11 @@ msgstr "" msgid "Submit this document to complete this step." msgstr "" -#: public/js/frappe/form/form.js:1216 +#: public/js/frappe/form/form.js:1220 msgid "Submit this document to confirm" msgstr "" -#: public/js/frappe/list/list_view.js:2042 +#: public/js/frappe/list/list_view.js:2044 msgctxt "Title of confirmation dialog" msgid "Submit {0} documents?" msgstr "" @@ -24482,7 +24511,7 @@ msgstr "" msgid "Suggested Indexes" msgstr "" -#: core/doctype/user/user.py:682 +#: core/doctype/user/user.py:689 msgid "Suggested Username: {0}" msgstr "" @@ -25005,7 +25034,7 @@ msgstr "" msgid "Templates" msgstr "" -#: core/doctype/user/user.py:978 +#: core/doctype/user/user.py:985 msgid "Temporarily Disabled" msgstr "" @@ -25161,7 +25190,11 @@ msgstr "" msgid "The comment cannot be empty" msgstr "" -#: public/js/frappe/list/list_view.js:627 +#: templates/emails/workflow_action.html:9 +msgid "The contents of this email are strictly confidential. Please do not forward this email to anyone." +msgstr "" + +#: public/js/frappe/list/list_view.js:629 msgid "The count shown is an estimated count. Click here to see the accurate count." msgstr "" @@ -25261,11 +25294,11 @@ msgid "" "" msgstr "" -#: core/doctype/user/user.py:938 +#: core/doctype/user/user.py:945 msgid "The reset password link has been expired" msgstr "" -#: core/doctype/user/user.py:940 +#: core/doctype/user/user.py:947 msgid "The reset password link has either been used before or is invalid" msgstr "" @@ -25510,11 +25543,11 @@ msgstr "" msgid "This document has been reverted" msgstr "" -#: public/js/frappe/form/form.js:1304 +#: public/js/frappe/form/form.js:1308 msgid "This document has unsaved changes which might not appear in final PDF.
    Consider saving the document before printing." msgstr "" -#: public/js/frappe/form/form.js:1097 +#: public/js/frappe/form/form.js:1101 msgid "This document is already amended, you cannot ammend it again" msgstr "" @@ -25550,7 +25583,7 @@ msgstr "" msgid "This file is public. It can be accessed without authentication." msgstr "" -#: public/js/frappe/form/form.js:1194 +#: public/js/frappe/form/form.js:1198 msgid "This form has been modified after you have loaded it" msgstr "" @@ -25697,7 +25730,7 @@ msgstr "" msgid "This will terminate the job immediately and might be dangerous, are you sure? " msgstr "" -#: core/doctype/user/user.py:1198 +#: core/doctype/user/user.py:1205 msgid "Throttled" msgstr "" @@ -26053,7 +26086,7 @@ msgstr "" msgid "To print output use print(text)" msgstr "" -#: core/doctype/user_type/user_type.py:295 +#: core/doctype/user_type/user_type.py:292 msgid "To set the role {0} in the user {1}, kindly set the {2} field as {3} in one of the {4} record." msgstr "" @@ -26120,7 +26153,7 @@ msgstr "" msgid "Toggle Sidebar" msgstr "" -#: public/js/frappe/list/list_view.js:1778 +#: public/js/frappe/list/list_view.js:1780 msgctxt "Button in list view menu" msgid "Toggle Sidebar" msgstr "" @@ -26167,7 +26200,7 @@ msgstr "" msgid "Too many changes to database in single action." msgstr "" -#: core/doctype/user/user.py:979 +#: core/doctype/user/user.py:986 msgid "Too many users signed up recently, so the registration is disabled. Please try back in an hour" msgstr "" @@ -26672,7 +26705,7 @@ msgstr "" msgid "Unable to open attached file. Did you export it as CSV?" msgstr "" -#: core/doctype/file/utils.py:97 core/doctype/file/utils.py:129 +#: core/doctype/file/utils.py:98 core/doctype/file/utils.py:130 msgid "Unable to read file format for {0}" msgstr "" @@ -27279,7 +27312,7 @@ msgstr "" msgid "User Id Field" msgstr "" -#: core/doctype/user_type/user_type.py:287 +#: core/doctype/user_type/user_type.py:284 msgid "User Id Field is mandatory in the user type {0}" msgstr "" @@ -27309,7 +27342,7 @@ msgstr "" msgid "User Permissions" msgstr "" -#: public/js/frappe/list/list_view.js:1736 +#: public/js/frappe/list/list_view.js:1738 msgctxt "Button in list view menu" msgid "User Permissions" msgstr "" @@ -27432,15 +27465,15 @@ msgstr "" msgid "User with email: {0} does not exist in the system. Please ask 'System Administrator' to create the user for you." msgstr "" -#: core/doctype/user/user.py:484 +#: core/doctype/user/user.py:491 msgid "User {0} cannot be deleted" msgstr "" -#: core/doctype/user/user.py:279 +#: core/doctype/user/user.py:285 msgid "User {0} cannot be disabled" msgstr "" -#: core/doctype/user/user.py:564 +#: core/doctype/user/user.py:571 msgid "User {0} cannot be renamed" msgstr "" @@ -27461,7 +27494,7 @@ msgstr "" msgid "User {0} has requested for data deletion" msgstr "" -#: core/doctype/user/user.py:1327 +#: core/doctype/user/user.py:1334 msgid "User {0} impersonated as {1}" msgstr "" @@ -27489,7 +27522,7 @@ msgstr "" msgid "Username" msgstr "" -#: core/doctype/user/user.py:649 +#: core/doctype/user/user.py:656 msgid "Username {0} already exists" msgstr "" @@ -27696,7 +27729,7 @@ msgstr "" msgid "Verdana" msgstr "" -#: twofactor.py:357 +#: twofactor.py:352 msgid "Verfication Code" msgstr "" @@ -28094,7 +28127,7 @@ msgstr "" #. Group in Module Def's connections #. Name of a Workspace #: core/doctype/module_def/module_def.json -#: email/doctype/newsletter/newsletter.py:449 +#: email/doctype/newsletter/newsletter.py:453 #: public/js/frappe/ui/toolbar/about.js:8 #: website/workspace/website/website.json msgid "Website" @@ -28332,11 +28365,11 @@ msgstr "" msgid "Welcome Workspace" msgstr "" -#: core/doctype/user/user.py:362 +#: core/doctype/user/user.py:369 msgid "Welcome email sent" msgstr "" -#: core/doctype/user/user.py:423 +#: core/doctype/user/user.py:430 msgid "Welcome to {0}" msgstr "" @@ -28759,7 +28792,7 @@ msgctxt "Name of the current user. For example: You edited this 5 hours ago." msgid "You" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:462 +#: public/js/frappe/form/footer/form_timeline.js:464 msgid "You Liked" msgstr "" @@ -28839,7 +28872,7 @@ msgstr "" msgid "You are selecting Sync Option as ALL, It will resync all read as well as unread message from server. This may also cause the duplication of Communication (emails)." msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:413 +#: public/js/frappe/form/footer/form_timeline.js:415 msgctxt "Form timeline" msgid "You attached {0}" msgstr "" @@ -28970,12 +29003,12 @@ msgstr "" msgid "You changed the values for {0} {1}" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:442 +#: public/js/frappe/form/footer/form_timeline.js:444 msgctxt "Form timeline" msgid "You changed {0} to {1}" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:138 +#: public/js/frappe/form/footer/form_timeline.js:140 #: public/js/frappe/form/sidebar/form_sidebar.js:106 msgid "You created this" msgstr "" @@ -29005,7 +29038,7 @@ msgstr "" msgid "You do not have permission to view this document" msgstr "" -#: public/js/frappe/form/form.js:955 +#: public/js/frappe/form/form.js:959 msgid "You do not have permissions to cancel all linked documents." msgstr "" @@ -29057,7 +29090,7 @@ msgstr "" msgid "You have received a ❤️ like on your blog post" msgstr "" -#: twofactor.py:448 +#: twofactor.py:432 msgid "You have to enable Two Factor Auth from System Settings." msgstr "" @@ -29085,7 +29118,7 @@ msgstr "" msgid "You hit the rate limit because of too many requests. Please try after sometime." msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:149 +#: public/js/frappe/form/footer/form_timeline.js:151 #: public/js/frappe/form/sidebar/form_sidebar.js:95 msgid "You last edited this" msgstr "" @@ -29158,7 +29191,7 @@ msgstr "" msgid "You need {0} permission to fetch values from {1} {2}" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:418 +#: public/js/frappe/form/footer/form_timeline.js:420 msgctxt "Form timeline" msgid "You removed attachment {0}" msgstr "" @@ -29185,7 +29218,7 @@ msgstr "" msgid "You unfollowed this document" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:182 +#: public/js/frappe/form/footer/form_timeline.js:184 msgid "You viewed this" msgstr "" @@ -30068,7 +30101,7 @@ msgstr "" msgid "{0} Google Contacts synced." msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:463 +#: public/js/frappe/form/footer/form_timeline.js:465 msgid "{0} Liked" msgstr "" @@ -30121,7 +30154,7 @@ msgstr "" msgid "{0} Tree" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:126 +#: public/js/frappe/form/footer/form_timeline.js:128 #: public/js/frappe/form/sidebar/form_sidebar.js:86 msgid "{0} Web page views" msgstr "" @@ -30193,7 +30226,7 @@ msgstr "" msgid "{0} assigned {1}: {2}" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:414 +#: public/js/frappe/form/footer/form_timeline.js:416 msgctxt "Form timeline" msgid "{0} attached {1}" msgstr "" @@ -30231,7 +30264,7 @@ msgstr "" msgid "{0} changed the values for {1} {2}" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:443 +#: public/js/frappe/form/footer/form_timeline.js:445 msgctxt "Form timeline" msgid "{0} changed {1} to {2}" msgstr "" @@ -30248,7 +30281,7 @@ msgstr "" msgid "{0} created successfully" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:139 +#: public/js/frappe/form/footer/form_timeline.js:141 #: public/js/frappe/form/sidebar/form_sidebar.js:107 msgid "{0} created this" msgstr "" @@ -30499,15 +30532,15 @@ msgstr "" msgid "{0} is within {1}" msgstr "" -#: public/js/frappe/list/list_view.js:1653 +#: public/js/frappe/list/list_view.js:1655 msgid "{0} items selected" msgstr "" -#: core/doctype/user/user.py:1336 +#: core/doctype/user/user.py:1343 msgid "{0} just impersonated as you. They gave this reason: {1}" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:150 +#: public/js/frappe/form/footer/form_timeline.js:152 #: public/js/frappe/form/sidebar/form_sidebar.js:96 msgid "{0} last edited this" msgstr "" @@ -30570,11 +30603,11 @@ msgstr "" msgid "{0} not found" msgstr "" -#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:1027 +#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:1029 msgid "{0} of {1}" msgstr "" -#: public/js/frappe/list/list_view.js:1029 +#: public/js/frappe/list/list_view.js:1031 msgid "{0} of {1} ({2} rows with children)" msgstr "" @@ -30611,7 +30644,7 @@ msgstr "" msgid "{0} records will be exported" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:419 +#: public/js/frappe/form/footer/form_timeline.js:421 msgctxt "Form timeline" msgid "{0} removed attachment {1}" msgstr "" @@ -30703,7 +30736,7 @@ msgstr "" msgid "{0} values selected" msgstr "" -#: public/js/frappe/form/footer/form_timeline.js:183 +#: public/js/frappe/form/footer/form_timeline.js:185 msgid "{0} viewed this" msgstr "" @@ -30747,7 +30780,7 @@ msgstr "" msgid "{0} {1} does not exist, select a new target to merge" msgstr "" -#: public/js/frappe/form/form.js:946 +#: public/js/frappe/form/form.js:950 msgid "{0} {1} is linked with the following submitted documents: {2}" msgstr "" From 9ed2271d1209c2591262d69ee1df962cd6ffbfb0 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 22 Jul 2024 16:24:23 +0200 Subject: [PATCH 120/176] chore: adapt webhook preview --- .../integrations/doctype/webhook/webhook.js | 26 ++++++----- .../integrations/doctype/webhook/webhook.json | 43 ++----------------- .../integrations/doctype/webhook/webhook.py | 37 +++++++--------- 3 files changed, 34 insertions(+), 72 deletions(-) diff --git a/frappe/integrations/doctype/webhook/webhook.js b/frappe/integrations/doctype/webhook/webhook.js index 9fad6150ab..168b4be446 100644 --- a/frappe/integrations/doctype/webhook/webhook.js +++ b/frappe/integrations/doctype/webhook/webhook.js @@ -79,12 +79,27 @@ frappe.webhook = { }; frappe.ui.form.on("Webhook", { + onload: (frm) => { + frm.preview_fields = frm.doc.__onload.preview_fields; + }, refresh: (frm) => { frappe.webhook.set_fieldname_select(frm); frm.set_query( "background_jobs_queue", "frappe.integrations.doctype.webhook.webhook.get_all_queues" ); + + if (frm.doc.webhook_doctype) { + frm.add_custom_button(__("Preview"), () => { + const args = { + doc: frm.doc, + doctype: frm.doc.webhook_doctype, + preview_fields: frm.preview_fields, + }; + let dialog = new frappe.views.RenderPreviewer(args); + return dialog; + }); + } }, request_structure: (frm) => { @@ -98,17 +113,6 @@ frappe.ui.form.on("Webhook", { enable_security: (frm) => { frm.toggle_reqd("webhook_secret", frm.doc.enable_security); }, - - preview_document: (frm) => { - frappe.call({ - method: "generate_preview", - doc: frm.doc, - callback: (r) => { - frm.refresh_field("meets_condition"); - frm.refresh_field("preview_request_body"); - }, - }); - }, }); frappe.ui.form.on("Webhook Data", { diff --git a/frappe/integrations/doctype/webhook/webhook.json b/frappe/integrations/doctype/webhook/webhook.json index 5ce16026fa..884f4429ba 100644 --- a/frappe/integrations/doctype/webhook/webhook.json +++ b/frappe/integrations/doctype/webhook/webhook.json @@ -30,13 +30,7 @@ "webhook_headers", "sb_webhook_data", "webhook_data", - "webhook_json", - "preview_tab", - "preview_document", - "column_break_26", - "meets_condition", - "section_break_28", - "preview_request_body" + "webhook_json" ], "fields": [ { @@ -169,37 +163,6 @@ "options": "POST\nPUT\nDELETE", "reqd": 1 }, - { - "fieldname": "preview_tab", - "fieldtype": "Tab Break", - "label": "Preview" - }, - { - "fieldname": "preview_document", - "fieldtype": "Dynamic Link", - "label": "Select Document", - "options": "webhook_doctype" - }, - { - "fieldname": "preview_request_body", - "fieldtype": "Code", - "is_virtual": 1, - "label": "Request Body" - }, - { - "fieldname": "meets_condition", - "fieldtype": "Data", - "is_virtual": 1, - "label": "Meets Condition?" - }, - { - "fieldname": "column_break_26", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_28", - "fieldtype": "Section Break" - }, { "default": "0", "description": "On checking this option, URL will be treated like a jinja template string", @@ -226,7 +189,7 @@ "link_fieldname": "webhook" } ], - "modified": "2024-03-23 16:04:03.108172", + "modified": "2024-07-22 09:23:32.642172", "modified_by": "Administrator", "module": "Integrations", "name": "Webhook", @@ -250,4 +213,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 9d82dd34b1..8ee5df1a25 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -36,9 +36,6 @@ class Webhook(Document): enable_security: DF.Check enabled: DF.Check is_dynamic_url: DF.Check - meets_condition: DF.Data | None - preview_document: DF.DynamicLink | None - preview_request_body: DF.Code | None request_method: DF.Literal["POST", "PUT", "DELETE"] request_structure: DF.Literal["", "Form URL-Encoded", "JSON"] request_url: DF.SmallText @@ -59,6 +56,15 @@ class Webhook(Document): webhook_secret: DF.Password | None # end: auto-generated types + def onload(self): + self.set_onload( + "preview_fields", + [ + {"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"}, + {"label": _("Request Body"), "fieldtype": "Code", "method": "preview_request_body"}, + ], + ) + def validate(self): self.validate_docevent() self.validate_condition() @@ -119,35 +125,24 @@ class Webhook(Document): frappe.throw(_("Invalid Webhook Secret")) @frappe.whitelist() - def generate_preview(self): - # This function doesn't need to do anything specific as virtual fields - # get evaluated automatically. - pass - - @property - def meets_condition(self): + def preview_meets_condition(self, preview_document): if not self.condition: return _("Yes") - - if not (self.preview_document and self.webhook_doctype): - return _("Select a document to check if it meets conditions.") - try: - doc = frappe.get_cached_doc(self.webhook_doctype, self.preview_document) + doc = frappe.get_cached_doc(self.webhook_doctype, preview_document) met_condition = frappe.safe_eval(self.condition, eval_locals=get_context(doc)) except Exception as e: + frappe.local.message_log = [] return _("Failed to evaluate conditions: {}").format(e) return _("Yes") if met_condition else _("No") - @property - def preview_request_body(self): - if not (self.preview_document and self.webhook_doctype): - return _("Select a document to preview request data") - + @frappe.whitelist() + def preview_request_body(self, preview_document): try: - doc = frappe.get_cached_doc(self.webhook_doctype, self.preview_document) + doc = frappe.get_cached_doc(self.webhook_doctype, preview_document) return frappe.as_json(get_webhook_data(doc, self)) except Exception as e: + frappe.local.message_log = [] return _("Failed to compute request body: {}").format(e) From b20942396b3c08aca3ada70b385833486b284b2c Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 24 Jul 2024 11:59:48 +0530 Subject: [PATCH 121/176] fix(query_report): don't crash if `execution_time` isn't defined Signed-off-by: Akhil Narang --- frappe/public/js/frappe/views/reports/query_report.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 0284639e6a..1332a186aa 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -462,7 +462,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { setup_progress_bar() { let seconds_elapsed = 0; - const execution_time = this.report_settings.execution_time || 0; + const execution_time = this.report_settings?.execution_time || 0; if (execution_time < 5) return; From 5acdc7870112a08dfa6fc60b62e34f599b83c0d4 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 24 Jul 2024 12:07:17 +0530 Subject: [PATCH 122/176] fix(script_helpers): prevent TypeError when cur_frm is null Signed-off-by: Akhil Narang --- frappe/public/js/frappe/form/script_helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/script_helpers.js b/frappe/public/js/frappe/form/script_helpers.js index 4f29a0a487..f47ce99ce6 100644 --- a/frappe/public/js/frappe/form/script_helpers.js +++ b/frappe/public/js/frappe/form/script_helpers.js @@ -33,7 +33,7 @@ window.refresh_field = function (n, docname, table_field) { }; window.set_field_options = function (n, txt) { - cur_frm.set_df_property(n, "options", txt); + cur_frm?.set_df_property(n, "options", txt); }; window.toggle_field = function (n, hidden) { From 1d46f03dae84b9afa425ffee33833c1c354ec268 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 24 Jul 2024 12:46:25 +0530 Subject: [PATCH 123/176] fix: check that query_string isn't null before trying to use it Signed-off-by: Akhil Narang --- frappe/website/path_resolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/website/path_resolver.py b/frappe/website/path_resolver.py index ebb0595056..4af49988c3 100644 --- a/frappe/website/path_resolver.py +++ b/frappe/website/path_resolver.py @@ -134,7 +134,7 @@ def resolve_redirect(path, query_string=None): for rule in redirects: pattern = rule["source"].strip("/ ") + "$" path_to_match = path - if rule.get("match_with_query_string"): + if query_string and rule.get("match_with_query_string"): path_to_match = path + "?" + frappe.safe_decode(query_string) try: From 95de3071b6f5c75392dd89c6002b7c8cb75d04bc Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 24 Jul 2024 13:32:07 +0530 Subject: [PATCH 124/176] fix: sync translations from crowdin (#27142) --- frappe/locale/eo.po | 663 +++++++++++++++++++++++++------------------- frappe/locale/sv.po | 663 +++++++++++++++++++++++++------------------- 2 files changed, 766 insertions(+), 560 deletions(-) diff --git a/frappe/locale/eo.po b/frappe/locale/eo.po index 7bd6eb076f..e10c29491e 100644 --- a/frappe/locale/eo.po +++ b/frappe/locale/eo.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-07-07 09:33+0000\n" -"PO-Revision-Date: 2024-07-10 16:24\n" +"POT-Creation-Date: 2024-07-21 09:33+0000\n" +"PO-Revision-Date: 2024-07-23 01:05\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Esperanto\n" "MIME-Version: 1.0\n" @@ -44,7 +44,7 @@ msgstr "crwdns90470:0crwdne90470:0" msgid "\"Team Members\" or \"Management\"" msgstr "crwdns127908:0crwdne127908:0" -#: public/js/frappe/form/form.js:1085 +#: public/js/frappe/form/form.js:1089 msgid "\"amended_from\" field must be present to do an amendment." msgstr "crwdns90474:0crwdne90474:0" @@ -98,7 +98,7 @@ msgstr "crwdns90532:0{0}crwdne90532:0" msgid "'{0}' not allowed for type {1} in row {2}" msgstr "crwdns90534:0{0}crwdnd90534:0{1}crwdnd90534:0{2}crwdne90534:0" -#: public/js/frappe/data_import/data_exporter.js:301 +#: public/js/frappe/data_import/data_exporter.js:302 msgid "(Mandatory)" msgstr "crwdns110776:0crwdne110776:0" @@ -168,7 +168,7 @@ msgstr "crwdns90558:0crwdne90558:0" msgid "1 month ago" msgstr "crwdns90560:0crwdne90560:0" -#: public/js/frappe/data_import/data_exporter.js:226 +#: public/js/frappe/data_import/data_exporter.js:227 msgid "1 record will be exported" msgstr "crwdns90562:0crwdne90562:0" @@ -471,7 +471,7 @@ msgid "

    To interact with above HTML you will have to use `root_element` as a p "" msgstr "crwdns127946:0crwdne127946:0" -#: twofactor.py:462 +#: twofactor.py:446 msgid "

    Your OTP secret on {0} has been reset. If you did not perform this reset and did not request it, please contact your System Administrator immediately.

    " msgstr "crwdns90622:0{0}crwdne90622:0" @@ -659,10 +659,11 @@ msgid "API Endpoint Args" msgstr "crwdns127990:0crwdne127990:0" #. Label of the api_key (Data) field in DocType 'User' +#. Label of the api_key (Data) field in DocType 'Email Account' #. Label of the api_key (Data) field in DocType 'Google Settings' #. Label of the sb_01 (Section Break) field in DocType 'Google Settings' #. Label of the api_key (Data) field in DocType 'Push Notification Settings' -#: core/doctype/user/user.json +#: core/doctype/user/user.json email/doctype/email_account/email_account.json #: integrations/doctype/google_settings/google_settings.json #: integrations/doctype/push_notification_settings/push_notification_settings.json msgid "API Key" @@ -685,9 +686,10 @@ msgid "API Method" msgstr "crwdns127998:0crwdne127998:0" #. Label of the api_secret (Password) field in DocType 'User' +#. Label of the api_secret (Password) field in DocType 'Email Account' #. Label of the api_secret (Password) field in DocType 'Push Notification #. Settings' -#: core/doctype/user/user.json +#: core/doctype/user/user.json email/doctype/email_account/email_account.json #: integrations/doctype/push_notification_settings/push_notification_settings.json msgid "API Secret" msgstr "crwdns128000:0crwdne128000:0" @@ -923,7 +925,7 @@ msgstr "crwdns90796:0crwdne90796:0" #. Group in User's connections #: core/doctype/user/user.json public/js/frappe/form/dashboard.js:22 -#: public/js/frappe/form/footer/form_timeline.js:58 +#: public/js/frappe/form/footer/form_timeline.js:60 msgid "Activity" msgstr "crwdns90798:0crwdne90798:0" @@ -952,11 +954,6 @@ msgstr "crwdns90804:0crwdne90804:0" msgid "Add" msgstr "crwdns90808:0crwdne90808:0" -#: public/js/frappe/list/list_view.js:266 -msgctxt "Primary action in list view" -msgid "Add" -msgstr "crwdns110784:0crwdne110784:0" - #: public/js/frappe/form/grid_row.js:431 msgid "Add / Remove Columns" msgstr "crwdns110786:0crwdne110786:0" @@ -994,6 +991,10 @@ msgstr "crwdns128032:0crwdne128032:0" msgid "Add Border at Top" msgstr "crwdns128034:0crwdne128034:0" +#: desk/doctype/number_card/number_card.js:36 +msgid "Add Card to Dashboard" +msgstr "crwdns142868:0crwdne142868:0" + #: public/js/frappe/views/reports/query_report.js:210 msgid "Add Chart to Dashboard" msgstr "crwdns90824:0crwdne90824:0" @@ -1068,7 +1069,7 @@ msgstr "crwdns128042:0crwdne128042:0" msgid "Add Review" msgstr "crwdns90850:0crwdne90850:0" -#: core/doctype/user/user.py:757 +#: core/doctype/user/user.py:772 msgid "Add Roles" msgstr "crwdns90852:0crwdne90852:0" @@ -1101,7 +1102,7 @@ msgstr "crwdns90862:0crwdne90862:0" msgid "Add Tags" msgstr "crwdns90864:0crwdne90864:0" -#: public/js/frappe/list/list_view.js:1903 +#: public/js/frappe/list/list_view.js:1957 msgctxt "Button in list view actions menu" msgid "Add Tags" msgstr "crwdns90866:0crwdne90866:0" @@ -1137,7 +1138,7 @@ msgstr "crwdns110792:0crwdne110792:0" msgid "Add a New Role" msgstr "crwdns110794:0crwdne110794:0" -#: public/js/frappe/form/form_tour.js:205 +#: public/js/frappe/form/form_tour.js:211 msgid "Add a Row" msgstr "crwdns90878:0crwdne90878:0" @@ -1187,7 +1188,7 @@ msgstr "crwdns90896:0crwdne90896:0" msgid "Add to table" msgstr "crwdns90898:0crwdne90898:0" -#: public/js/frappe/form/footer/form_timeline.js:97 +#: public/js/frappe/form/footer/form_timeline.js:99 msgid "Add to this activity by mailing to {0}" msgstr "crwdns90900:0{0}crwdne90900:0" @@ -1195,6 +1196,11 @@ msgstr "crwdns90900:0{0}crwdne90900:0" msgid "Add {0}" msgstr "crwdns110798:0{0}crwdne110798:0" +#: public/js/frappe/list/list_view.js:264 +msgctxt "Primary action in list view" +msgid "Add {0}" +msgstr "crwdns142870:0{0}crwdne142870:0" + #. Description of the '<head> HTML' (Code) field in DocType 'Website #. Settings' #: website/doctype/website_settings/website_settings.json @@ -1218,8 +1224,11 @@ msgstr "crwdns90908:0{0}crwdnd90908:0{1}crwdne90908:0" #. DocPerm' #. Label of the additional_permissions (Section Break) field in DocType #. 'DocPerm' +#. Label of the additional_permissions_section (Section Break) field in DocType +#. 'User Document Type' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json +#: core/doctype/user_document_type/user_document_type.json msgid "Additional Permissions" msgstr "crwdns128056:0crwdne128056:0" @@ -1314,11 +1323,11 @@ msgstr "crwdns90948:0crwdne90948:0" msgid "Administrator" msgstr "crwdns90950:0crwdne90950:0" -#: core/doctype/user/user.py:1161 +#: core/doctype/user/user.py:1176 msgid "Administrator Logged In" msgstr "crwdns90952:0crwdne90952:0" -#: core/doctype/user/user.py:1155 +#: core/doctype/user/user.py:1170 msgid "Administrator accessed {0} on {1} via IP Address {2}." msgstr "crwdns90954:0{0}crwdnd90954:0{1}crwdnd90954:0{2}crwdne90954:0" @@ -1474,7 +1483,7 @@ msgstr "crwdns91012:0crwdne91012:0" msgid "All Records" msgstr "crwdns91014:0crwdne91014:0" -#: public/js/frappe/form/form.js:2225 +#: public/js/frappe/form/form.js:2230 msgid "All Submissions" msgstr "crwdns110800:0crwdne110800:0" @@ -1792,11 +1801,11 @@ msgstr "crwdns128188:0crwdne128188:0" msgid "Allowed Roles" msgstr "crwdns128190:0crwdne128190:0" -#: public/js/frappe/form/form.js:1251 +#: public/js/frappe/form/form.js:1255 msgid "Allowing DocType, DocType. Be careful!" msgstr "crwdns91150:0crwdne91150:0" -#: core/doctype/user/user.py:964 +#: core/doctype/user/user.py:979 msgid "Already Registered" msgstr "crwdns91152:0crwdne91152:0" @@ -2008,11 +2017,11 @@ msgstr "crwdns91230:0crwdne91230:0" msgid "App Secret Key" msgstr "crwdns128236:0crwdne128236:0" -#: modules/utils.py:275 +#: modules/utils.py:279 msgid "App not found for module: {0}" msgstr "crwdns91240:0{0}crwdne91240:0" -#: __init__.py:1794 +#: __init__.py:1800 msgid "App {0} is not installed" msgstr "crwdns91242:0{0}crwdne91242:0" @@ -2032,7 +2041,7 @@ msgstr "crwdns128238:0crwdne128238:0" msgid "Append To" msgstr "crwdns128240:0crwdne128240:0" -#: email/doctype/email_account/email_account.py:185 +#: email/doctype/email_account/email_account.py:195 msgid "Append To can be one of {0}" msgstr "crwdns91252:0{0}crwdne91252:0" @@ -2073,7 +2082,7 @@ msgstr "crwdns128250:0crwdne128250:0" msgid "Applied On" msgstr "crwdns128252:0crwdne128252:0" -#: public/js/frappe/list/list_view.js:1888 +#: public/js/frappe/list/list_view.js:1942 msgctxt "Button in list view actions menu" msgid "Apply Assignment Rule" msgstr "crwdns91270:0crwdne91270:0" @@ -2167,7 +2176,7 @@ msgstr "crwdns128272:0crwdne128272:0" msgid "Archived Columns" msgstr "crwdns91306:0crwdne91306:0" -#: public/js/frappe/list/list_view.js:1867 +#: public/js/frappe/list/list_view.js:1921 msgid "Are you sure you want to clear the assignments?" msgstr "crwdns104470:0crwdne104470:0" @@ -2263,7 +2272,7 @@ msgstr "crwdns128278:0crwdne128278:0" msgid "Assign To" msgstr "crwdns91344:0crwdne91344:0" -#: public/js/frappe/list/list_view.js:1849 +#: public/js/frappe/list/list_view.js:1903 msgctxt "Button in list view actions menu" msgid "Assign To" msgstr "crwdns91346:0crwdne91346:0" @@ -2382,7 +2391,7 @@ msgstr "crwdns91400:0{0}crwdne91400:0" msgid "Assignment Rules" msgstr "crwdns128292:0crwdne128292:0" -#: desk/doctype/notification_log/notification_log.py:157 +#: desk/doctype/notification_log/notification_log.py:158 msgid "Assignment Update on {0}" msgstr "crwdns91404:0{0}crwdne91404:0" @@ -2570,7 +2579,15 @@ msgstr "crwdns91494:0crwdne91494:0" msgid "Authentication Apps you can use are: " msgstr "crwdns91498:0crwdne91498:0" -#: email/doctype/email_account/email_account.py:312 +#: email/frappemail.py:89 +msgid "Authentication Error: Invalid API Key or Secret" +msgstr "crwdns142872:0crwdne142872:0" + +#: email/frappemail.py:85 +msgid "Authentication Error: Reauthorize OAuth for Email Account {0}." +msgstr "crwdns142874:0{0}crwdne142874:0" + +#: email/doctype/email_account/email_account.py:328 msgid "Authentication failed while receiving emails from Email Account: {0}." msgstr "crwdns91500:0{0}crwdne91500:0" @@ -2784,11 +2801,11 @@ msgstr "crwdns128362:0crwdne128362:0" msgid "Automatic" msgstr "crwdns91588:0crwdne91588:0" -#: email/doctype/email_account/email_account.py:715 +#: email/doctype/email_account/email_account.py:766 msgid "Automatic Linking can be activated only for one Email Account." msgstr "crwdns91592:0crwdne91592:0" -#: email/doctype/email_account/email_account.py:709 +#: email/doctype/email_account/email_account.py:760 msgid "Automatic Linking can be activated only if Incoming is enabled." msgstr "crwdns91594:0crwdne91594:0" @@ -3826,7 +3843,7 @@ msgstr "crwdns92008:0{0}crwdnd92008:0{1}crwdnd92008:0{0}crwdne92008:0" msgid "Cancel" msgstr "crwdns92010:0crwdne92010:0" -#: public/js/frappe/list/list_view.js:1958 +#: public/js/frappe/list/list_view.js:2012 msgctxt "Button in list view actions menu" msgid "Cancel" msgstr "crwdns92012:0crwdne92012:0" @@ -3836,11 +3853,11 @@ msgctxt "Secondary button in warning dialog" msgid "Cancel" msgstr "crwdns92022:0crwdne92022:0" -#: public/js/frappe/form/form.js:974 +#: public/js/frappe/form/form.js:978 msgid "Cancel All" msgstr "crwdns92026:0crwdne92026:0" -#: public/js/frappe/form/form.js:961 +#: public/js/frappe/form/form.js:965 msgid "Cancel All Documents" msgstr "crwdns92028:0crwdne92028:0" @@ -3848,7 +3865,7 @@ msgstr "crwdns92028:0crwdne92028:0" msgid "Cancel Scheduling" msgstr "crwdns92030:0crwdne92030:0" -#: public/js/frappe/list/list_view.js:1963 +#: public/js/frappe/list/list_view.js:2017 msgctxt "Title of confirmation dialog" msgid "Cancel {0} documents?" msgstr "crwdns92032:0{0}crwdne92032:0" @@ -3948,7 +3965,7 @@ msgstr "crwdns92082:0crwdne92082:0" msgid "Cannot delete Home and Attachments folders" msgstr "crwdns92084:0crwdne92084:0" -#: model/delete_doc.py:373 +#: model/delete_doc.py:382 msgid "Cannot delete or cancel because {0} {1} is linked with {2} {3} {4}" msgstr "crwdns92086:0{0}crwdnd92086:0{1}crwdnd92086:0{2}crwdnd92086:0{3}crwdnd92086:0{4}crwdne92086:0" @@ -4061,9 +4078,9 @@ msgstr "crwdns92136:0crwdne92136:0" msgid "Cannot set 'Report' permission if 'Only If Creator' permission is set" msgstr "crwdns110830:0crwdne110830:0" -#: email/doctype/notification/notification.py:138 -msgid "Cannot set Notification on Document Type {0}" -msgstr "crwdns92138:0{0}crwdne92138:0" +#: email/doctype/notification/notification.py:139 +msgid "Cannot set Notification with event {0} on Document Type {1}" +msgstr "crwdns142876:0{0}crwdnd142876:0{1}crwdne142876:0" #: core/doctype/docshare/docshare.py:67 msgid "Cannot share {0} with submit permission as the doctype {1} is not submittable" @@ -4409,7 +4426,7 @@ msgstr "crwdns92296:0crwdne92296:0" msgid "Clear & Add template" msgstr "crwdns92298:0crwdne92298:0" -#: public/js/frappe/list/list_view.js:1864 +#: public/js/frappe/list/list_view.js:1918 msgctxt "Button in list view actions menu" msgid "Clear Assignment" msgstr "crwdns104478:0crwdne104478:0" @@ -4508,7 +4525,7 @@ msgstr "crwdns110842:0crwdne110842:0" msgid "Click to Set Filters" msgstr "crwdns110844:0crwdne110844:0" -#: public/js/frappe/list/list_view.js:680 +#: public/js/frappe/list/list_view.js:679 msgid "Click to sort by {0}" msgstr "crwdns110846:0{0}crwdne110846:0" @@ -4588,7 +4605,8 @@ msgid "Client URLs" msgstr "crwdns128656:0crwdne128656:0" #: core/doctype/communication/communication.js:39 desk/doctype/todo/todo.js:23 -#: public/js/frappe/ui/messages.js:243 website/js/bootstrap-4.js:24 +#: public/js/frappe/form/form_tour.js:17 public/js/frappe/ui/messages.js:244 +#: website/js/bootstrap-4.js:24 msgid "Close" msgstr "crwdns92372:0crwdne92372:0" @@ -4643,7 +4661,7 @@ msgstr "crwdns128666:0crwdne128666:0" msgid "Code challenge method" msgstr "crwdns128668:0crwdne128668:0" -#: public/js/frappe/form/form_tour.js:270 +#: public/js/frappe/form/form_tour.js:276 #: public/js/frappe/widgets/base_widget.js:159 msgid "Collapse" msgstr "crwdns92400:0crwdne92400:0" @@ -4945,7 +4963,7 @@ msgstr "crwdns92554:0crwdne92554:0" msgid "Complete By" msgstr "crwdns92558:0crwdne92558:0" -#: core/doctype/user/user.py:426 templates/emails/new_user.html:10 +#: core/doctype/user/user.py:432 templates/emails/new_user.html:10 msgid "Complete Registration" msgstr "crwdns92560:0crwdne92560:0" @@ -5507,7 +5525,7 @@ msgstr "crwdns128770:0crwdne128770:0" msgid "Create New" msgstr "crwdns92808:0crwdne92808:0" -#: public/js/frappe/list/list_view.js:487 +#: public/js/frappe/list/list_view.js:484 msgctxt "Create a new document from list view" msgid "Create New" msgstr "crwdns110866:0crwdne110866:0" @@ -5547,7 +5565,7 @@ msgstr "crwdns92822:0crwdne92822:0" #: public/js/frappe/form/controls/link.js:295 #: public/js/frappe/form/controls/link.js:297 #: public/js/frappe/form/link_selector.js:139 -#: public/js/frappe/list/list_view.js:476 +#: public/js/frappe/list/list_view.js:473 #: public/js/frappe/web_form/web_form_list.js:225 msgid "Create a new {0}" msgstr "crwdns92824:0{0}crwdne92824:0" @@ -5574,7 +5592,7 @@ msgstr "crwdns92828:0crwdne92828:0" msgid "Create or Edit Workflow" msgstr "crwdns92830:0crwdne92830:0" -#: public/js/frappe/list/list_view.js:479 +#: public/js/frappe/list/list_view.js:476 msgid "Create your first {0}" msgstr "crwdns92832:0{0}crwdne92832:0" @@ -5605,7 +5623,7 @@ msgid "Created Custom Field {0} in {1}" msgstr "crwdns92844:0{0}crwdnd92844:0{1}crwdne92844:0" #: desk/doctype/dashboard_chart/dashboard_chart.js:241 -#: email/doctype/notification/notification.js:30 model/meta.py:46 +#: email/doctype/notification/notification.js:33 model/meta.py:46 #: public/js/frappe/model/meta.js:198 public/js/frappe/model/model.js:125 #: public/js/frappe/views/dashboard/dashboard_view.js:478 msgid "Created On" @@ -5964,7 +5982,7 @@ msgstr "crwdns93010:0crwdne93010:0" msgid "Customizations Reset" msgstr "crwdns93012:0crwdne93012:0" -#: modules/utils.py:91 +#: modules/utils.py:95 msgid "Customizations for {0} exported to:
    {1}" msgstr "crwdns93014:0{0}crwdnd93014:0{1}crwdne93014:0" @@ -5975,7 +5993,7 @@ msgstr "crwdns93014:0{0}crwdnd93014:0{1}crwdne93014:0" msgid "Customize" msgstr "crwdns93016:0crwdne93016:0" -#: public/js/frappe/list/list_view.js:1709 +#: public/js/frappe/list/list_view.js:1763 msgctxt "Button in list view menu" msgid "Customize" msgstr "crwdns93018:0crwdne93018:0" @@ -5990,6 +6008,7 @@ msgstr "crwdns93022:0crwdne93022:0" #. Name of a DocType #: automation/doctype/auto_repeat/auto_repeat.js:33 +#: core/doctype/doctype/doctype.js:65 #: custom/doctype/customize_form/customize_form.json #: public/js/frappe/views/kanban/kanban_view.js:343 msgid "Customize Form" @@ -6220,7 +6239,7 @@ msgstr "crwdns128844:0crwdne128844:0" msgid "Data" msgstr "crwdns93122:0crwdne93122:0" -#: public/js/frappe/form/controls/data.js:58 +#: public/js/frappe/form/controls/data.js:59 msgid "Data Clipped" msgstr "crwdns93148:0crwdne93148:0" @@ -6325,6 +6344,7 @@ msgstr "crwdns128854:0crwdne128854:0" #. Trail' #: core/doctype/audit_trail/audit_trail.json #: desk/page/leaderboard/leaderboard.js:165 +#: public/js/frappe/widgets/chart_widget.js:237 msgid "Date Range" msgstr "crwdns93198:0crwdne93198:0" @@ -6458,7 +6478,7 @@ msgstr "crwdns93266:0crwdne93266:0" #. Label of the default_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:201 +#: email/doctype/email_account/email_account.py:217 msgid "Default Incoming" msgstr "crwdns93268:0crwdne93268:0" @@ -6478,7 +6498,7 @@ msgstr "crwdns128876:0crwdne128876:0" #. Label of the default_outgoing (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:209 +#: email/doctype/email_account/email_account.py:225 msgid "Default Outgoing" msgstr "crwdns93278:0crwdne93278:0" @@ -6593,7 +6613,7 @@ msgstr "crwdns93326:0crwdne93326:0" msgid "Defaults" msgstr "crwdns128906:0crwdne128906:0" -#: email/doctype/email_account/email_account.py:220 +#: email/doctype/email_account/email_account.py:236 msgid "Defaults Updated" msgstr "crwdns93332:0crwdne93332:0" @@ -6619,7 +6639,7 @@ msgstr "crwdns128908:0crwdne128908:0" #: core/doctype/docperm/docperm.json #: core/doctype/user_document_type/user_document_type.json #: core/doctype/user_permission/user_permission_list.js:189 -#: public/js/frappe/form/footer/form_timeline.js:613 +#: public/js/frappe/form/footer/form_timeline.js:615 #: public/js/frappe/form/grid.js:63 public/js/frappe/form/toolbar.js:434 #: public/js/frappe/views/reports/report_view.js:1654 #: public/js/frappe/views/treeview.js:308 @@ -6629,7 +6649,7 @@ msgstr "crwdns128908:0crwdne128908:0" msgid "Delete" msgstr "crwdns93336:0crwdne93336:0" -#: public/js/frappe/list/list_view.js:1926 +#: public/js/frappe/list/list_view.js:1980 msgctxt "Button in list view actions menu" msgid "Delete" msgstr "crwdns93338:0crwdne93338:0" @@ -6658,7 +6678,7 @@ msgstr "crwdns93352:0crwdne93352:0" msgid "Delete and Generate New" msgstr "crwdns110882:0crwdne110882:0" -#: public/js/frappe/form/footer/form_timeline.js:719 +#: public/js/frappe/form/footer/form_timeline.js:721 msgid "Delete comment?" msgstr "crwdns93354:0crwdne93354:0" @@ -6666,12 +6686,12 @@ msgstr "crwdns93354:0crwdne93354:0" msgid "Delete this record to allow sending to this email address" msgstr "crwdns93356:0crwdne93356:0" -#: public/js/frappe/list/list_view.js:1931 +#: public/js/frappe/list/list_view.js:1985 msgctxt "Title of confirmation dialog" msgid "Delete {0} item permanently?" msgstr "crwdns93358:0{0}crwdne93358:0" -#: public/js/frappe/list/list_view.js:1937 +#: public/js/frappe/list/list_view.js:1991 msgctxt "Title of confirmation dialog" msgid "Delete {0} items permanently?" msgstr "crwdns93360:0{0}crwdne93360:0" @@ -6910,7 +6930,7 @@ msgstr "crwdns93458:0crwdne93458:0" #: desk/doctype/event/event.json #: desk/page/user_profile/user_profile_sidebar.html:45 #: public/js/form_builder/store.js:259 public/js/form_builder/utils.js:38 -#: public/js/frappe/form/layout.js:135 public/js/frappe/views/treeview.js:271 +#: public/js/frappe/form/layout.js:137 public/js/frappe/views/treeview.js:271 msgid "Details" msgstr "crwdns93460:0crwdne93460:0" @@ -7058,7 +7078,7 @@ msgstr "crwdns128970:0crwdne128970:0" msgid "Disabled" msgstr "crwdns93510:0crwdne93510:0" -#: email/doctype/email_account/email_account.js:232 +#: email/doctype/email_account/email_account.js:261 msgid "Disabled Auto Reply" msgstr "crwdns93536:0crwdne93536:0" @@ -7075,7 +7095,7 @@ msgctxt "Button in web form" msgid "Discard" msgstr "crwdns110884:0crwdne110884:0" -#: public/js/frappe/form/form.js:840 +#: public/js/frappe/form/form.js:844 msgid "Discard {0}" msgstr "crwdns127626:0{0}crwdne127626:0" @@ -7102,7 +7122,7 @@ msgstr "crwdns93542:0crwdne93542:0" msgid "Discussion Topic" msgstr "crwdns93544:0crwdne93544:0" -#: public/js/frappe/form/footer/form_timeline.js:623 +#: public/js/frappe/form/footer/form_timeline.js:625 #: templates/discussions/reply_card.html:16 #: templates/discussions/reply_section.html:29 msgid "Dismiss" @@ -7153,7 +7173,7 @@ msgstr "crwdns93562:0{0}crwdne93562:0" msgid "Do you still want to proceed?" msgstr "crwdns93564:0crwdne93564:0" -#: public/js/frappe/form/form.js:953 +#: public/js/frappe/form/form.js:957 msgid "Do you want to cancel all linked documents?" msgstr "crwdns93566:0crwdne93566:0" @@ -7328,11 +7348,11 @@ msgstr "crwdns128994:0crwdne128994:0" msgid "DocType required" msgstr "crwdns93652:0crwdne93652:0" -#: modules/utils.py:170 +#: modules/utils.py:174 msgid "DocType {0} does not exist." msgstr "crwdns93654:0{0}crwdne93654:0" -#: modules/utils.py:233 +#: modules/utils.py:237 msgid "DocType {} not found" msgstr "crwdns93656:0crwdne93656:0" @@ -7438,7 +7458,7 @@ msgstr "crwdns93702:0#{0}crwdne93702:0" #: core/doctype/user_permission/user_permission_list.js:36 #: core/doctype/version/version.json desk/doctype/tag_link/tag_link.json #: email/doctype/document_follow/document_follow.json -#: public/js/frappe/form/form_tour.js:60 +#: public/js/frappe/form/form_tour.js:62 msgid "Document Name" msgstr "crwdns93704:0crwdne93704:0" @@ -7622,15 +7642,15 @@ msgstr "crwdns129022:0crwdne129022:0" msgid "Document Unlocked" msgstr "crwdns93812:0crwdne93812:0" -#: public/js/frappe/list/list_view.js:1081 +#: public/js/frappe/list/list_view.js:1118 msgid "Document has been cancelled" msgstr "crwdns93814:0crwdne93814:0" -#: public/js/frappe/list/list_view.js:1080 +#: public/js/frappe/list/list_view.js:1117 msgid "Document has been submitted" msgstr "crwdns93816:0crwdne93816:0" -#: public/js/frappe/list/list_view.js:1079 +#: public/js/frappe/list/list_view.js:1116 msgid "Document is in draft state" msgstr "crwdns93818:0crwdne93818:0" @@ -7753,7 +7773,7 @@ msgstr "crwdns129038:0crwdne129038:0" msgid "Don't have an account?" msgstr "crwdns93874:0crwdne93874:0" -#: public/js/frappe/ui/messages.js:231 +#: public/js/frappe/form/form_tour.js:16 public/js/frappe/ui/messages.js:231 #: public/js/onboarding_tours/onboarding_tours.js:17 msgid "Done" msgstr "crwdns93876:0crwdne93876:0" @@ -7992,8 +8012,8 @@ msgstr "crwdns93972:0crwdne93972:0" #: printing/page/print_format_builder_beta/print_format_builder_beta.js:46 #: printing/page/print_format_builder_beta/print_format_builder_beta.js:85 #: public/js/frappe/form/controls/markdown_editor.js:31 -#: public/js/frappe/form/footer/form_timeline.js:652 -#: public/js/frappe/form/footer/form_timeline.js:661 +#: public/js/frappe/form/footer/form_timeline.js:654 +#: public/js/frappe/form/footer/form_timeline.js:663 #: public/js/frappe/form/templates/address_list.html:7 #: public/js/frappe/form/templates/contact_list.html:7 #: public/js/frappe/form/toolbar.js:681 @@ -8002,7 +8022,7 @@ msgstr "crwdns93972:0crwdne93972:0" #: public/js/frappe/views/workspace/workspace.js:460 #: public/js/frappe/views/workspace/workspace.js:816 #: public/js/frappe/widgets/base_widget.js:64 -#: public/js/frappe/widgets/chart_widget.js:298 +#: public/js/frappe/widgets/chart_widget.js:299 #: public/js/frappe/widgets/number_card_widget.js:331 #: templates/discussions/reply_card.html:29 #: templates/discussions/reply_section.html:29 @@ -8011,7 +8031,7 @@ msgstr "crwdns93972:0crwdne93972:0" msgid "Edit" msgstr "crwdns93974:0crwdne93974:0" -#: public/js/frappe/list/list_view.js:2012 +#: public/js/frappe/list/list_view.js:2066 msgctxt "Button in list view actions menu" msgid "Edit" msgstr "crwdns93976:0crwdne93976:0" @@ -8041,7 +8061,7 @@ msgstr "crwdns93982:0crwdne93982:0" msgid "Edit DocType" msgstr "crwdns93984:0crwdne93984:0" -#: public/js/frappe/list/list_view.js:1736 +#: public/js/frappe/list/list_view.js:1790 msgctxt "Button in list view menu" msgid "Edit DocType" msgstr "crwdns93986:0crwdne93986:0" @@ -8187,6 +8207,7 @@ msgstr "crwdns129070:0crwdne129070:0" #. Label of the email_tab (Tab Break) field in DocType 'System Settings' #. Label of the email (Data) field in DocType 'User' #. Label of the email_settings (Section Break) field in DocType 'User' +#. Label of the email (Check) field in DocType 'User Document Type' #. Label of the email (Data) field in DocType 'Event Participants' #. Label of the email (Data) field in DocType 'Email Group Member' #. Label of the email (Data) field in DocType 'Email Unsubscribe' @@ -8199,6 +8220,7 @@ msgstr "crwdns129070:0crwdne129070:0" #: core/doctype/success_action/success_action.js:57 #: core/doctype/system_settings/system_settings.json #: core/doctype/user/user.json +#: core/doctype/user_document_type/user_document_type.json #: desk/doctype/event_participants/event_participants.json #: email/doctype/email_group_member/email_group_member.json #: email/doctype/email_unsubscribe/email_unsubscribe.json @@ -8234,7 +8256,7 @@ msgctxt "Email Account" msgid "Email Account" msgstr "crwdns94060:0crwdne94060:0" -#: email/doctype/email_account/email_account.py:316 +#: email/doctype/email_account/email_account.py:332 msgid "Email Account Disabled." msgstr "crwdns94072:0crwdne94072:0" @@ -8243,7 +8265,7 @@ msgstr "crwdns94072:0crwdne94072:0" msgid "Email Account Name" msgstr "crwdns129072:0crwdne129072:0" -#: core/doctype/user/user.py:690 +#: core/doctype/user/user.py:705 msgid "Email Account added multiple times" msgstr "crwdns94076:0crwdne94076:0" @@ -8539,7 +8561,7 @@ msgstr "crwdns129124:0crwdne129124:0" #. Label of the enable_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:202 +#: email/doctype/email_account/email_account.py:218 msgid "Enable Incoming" msgstr "crwdns94210:0crwdne94210:0" @@ -8552,7 +8574,7 @@ msgstr "crwdns129126:0crwdne129126:0" #. Label of the enable_outgoing (Check) field in DocType 'Email Account' #: core/doctype/user_email/user_email.json #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:210 +#: email/doctype/email_account/email_account.py:226 msgid "Enable Outgoing" msgstr "crwdns94216:0crwdne94216:0" @@ -8623,7 +8645,7 @@ msgstr "crwdns94244:0crwdne94244:0" #. Label of the enable_two_factor_auth (Check) field in DocType 'System #. Settings' -#: core/doctype/system_settings/system_settings.json twofactor.py:449 +#: core/doctype/system_settings/system_settings.json twofactor.py:433 msgid "Enable Two Factor Auth" msgstr "crwdns94246:0crwdne94246:0" @@ -8692,7 +8714,7 @@ msgstr "crwdns94262:0crwdne94262:0" msgid "Enabled Scheduler" msgstr "crwdns94290:0crwdne94290:0" -#: email/doctype/email_account/email_account.py:936 +#: email/doctype/email_account/email_account.py:987 msgid "Enabled email inbox for user {0}" msgstr "crwdns94292:0{0}crwdne94292:0" @@ -8705,7 +8727,7 @@ msgstr "crwdns94292:0{0}crwdne94292:0" msgid "Enables Calendar and Gantt views." msgstr "crwdns129154:0crwdne129154:0" -#: email/doctype/email_account/email_account.js:227 +#: email/doctype/email_account/email_account.js:256 msgid "Enabling auto reply on an incoming email account will send automated replies to all the synchronized emails. Do you wish to continue?" msgstr "crwdns94300:0crwdne94300:0" @@ -8803,7 +8825,7 @@ msgstr "crwdns94340:0crwdne94340:0" msgid "Energy Point Settings" msgstr "crwdns94344:0crwdne94344:0" -#: desk/doctype/notification_log/notification_log.py:159 +#: desk/doctype/notification_log/notification_log.py:160 msgid "Energy Point Update on {0}" msgstr "crwdns94346:0{0}crwdne94346:0" @@ -8813,6 +8835,8 @@ msgstr "crwdns94346:0{0}crwdne94346:0" #. 'Notification Settings' #: desk/doctype/notification_settings/notification_settings.json #: desk/page/user_profile/user_profile.html:28 +#: desk/page/user_profile/user_profile_controller.js:80 +#: desk/page/user_profile/user_profile_controller.js:114 #: desk/page/user_profile/user_profile_controller.js:402 #: templates/emails/energy_points_summary.html:39 msgid "Energy Points" @@ -8853,7 +8877,7 @@ msgctxt "Title of prompt dialog" msgid "Enter Value" msgstr "crwdns94362:0crwdne94362:0" -#: public/js/frappe/form/form_tour.js:58 +#: public/js/frappe/form/form_tour.js:60 msgid "Enter a name for this {0}" msgstr "crwdns94364:0{0}crwdne94364:0" @@ -8884,7 +8908,7 @@ msgstr "crwdns129182:0crwdne129182:0" msgid "Enter url parameter for receiver nos" msgstr "crwdns129184:0crwdne129184:0" -#: public/js/frappe/ui/messages.js:332 +#: public/js/frappe/ui/messages.js:334 msgid "Enter your password" msgstr "crwdns94376:0crwdne94376:0" @@ -8975,9 +8999,9 @@ msgstr "crwdns94422:0crwdne94422:0" msgid "Error in Header/Footer Script" msgstr "crwdns110924:0crwdne110924:0" -#: email/doctype/notification/notification.py:395 -#: email/doctype/notification/notification.py:511 -#: email/doctype/notification/notification.py:517 +#: email/doctype/notification/notification.py:443 +#: email/doctype/notification/notification.py:559 +#: email/doctype/notification/notification.py:565 msgid "Error in Notification" msgstr "crwdns94424:0crwdne94424:0" @@ -8985,11 +9009,11 @@ msgstr "crwdns94424:0crwdne94424:0" msgid "Error in print format on line {0}: {1}" msgstr "crwdns94426:0{0}crwdnd94426:0{1}crwdne94426:0" -#: email/doctype/email_account/email_account.py:614 +#: email/doctype/email_account/email_account.py:664 msgid "Error while connecting to email account {0}" msgstr "crwdns94428:0{0}crwdne94428:0" -#: email/doctype/notification/notification.py:508 +#: email/doctype/notification/notification.py:556 msgid "Error while evaluating Notification {0}. Please fix your template." msgstr "crwdns94430:0{0}crwdne94430:0" @@ -9218,19 +9242,19 @@ msgstr "crwdns129232:0crwdne129232:0" #. Label of the export (Check) field in DocType 'DocPerm' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json core/doctype/recorder/recorder_list.js:37 -#: public/js/frappe/data_import/data_exporter.js:91 -#: public/js/frappe/data_import/data_exporter.js:242 +#: public/js/frappe/data_import/data_exporter.js:92 +#: public/js/frappe/data_import/data_exporter.js:243 #: public/js/frappe/views/reports/query_report.js:1669 #: public/js/frappe/views/reports/report_view.js:1550 msgid "Export" msgstr "crwdns94526:0crwdne94526:0" -#: public/js/frappe/list/list_view.js:2034 +#: public/js/frappe/list/list_view.js:2088 msgctxt "Button in list view actions menu" msgid "Export" msgstr "crwdns94528:0crwdne94528:0" -#: public/js/frappe/data_import/data_exporter.js:244 +#: public/js/frappe/data_import/data_exporter.js:245 msgid "Export 1 record" msgstr "crwdns94534:0crwdne94534:0" @@ -9303,7 +9327,7 @@ msgstr "crwdns129236:0crwdne129236:0" msgid "Export without main header" msgstr "crwdns129238:0crwdne129238:0" -#: public/js/frappe/data_import/data_exporter.js:246 +#: public/js/frappe/data_import/data_exporter.js:247 msgid "Export {0} records" msgstr "crwdns94564:0{0}crwdne94564:0" @@ -9456,7 +9480,7 @@ msgstr "crwdns94620:0crwdne94620:0" msgid "Failed to optimize image: {0}" msgstr "crwdns94622:0{0}crwdne94622:0" -#: email/doctype/email_queue/email_queue.py:281 +#: email/doctype/email_queue/email_queue.py:294 msgid "Failed to send email with subject:" msgstr "crwdns94624:0crwdne94624:0" @@ -9636,10 +9660,14 @@ msgstr "crwdns94704:0{0}crwdnd94704:0{1}crwdne94704:0" msgid "Field {0} is referring to non-existing doctype {1}." msgstr "crwdns94706:0{0}crwdnd94706:0{1}crwdne94706:0" -#: public/js/frappe/form/form.js:1761 +#: public/js/frappe/form/form.js:1765 msgid "Field {0} not found." msgstr "crwdns94708:0{0}crwdne94708:0" +#: email/doctype/notification/notification.py:348 +msgid "Field {0} on document {1} is neither a Mobile number field nor a Customer or User link" +msgstr "crwdns142910:0{0}crwdnd142910:0{1}crwdne142910:0" + #. Label of the fieldname (Data) field in DocType 'Report Column' #. Label of the fieldname (Data) field in DocType 'Report Filter' #. Label of the fieldname (Data) field in DocType 'Custom Field' @@ -9772,7 +9800,7 @@ msgctxt "File" msgid "File" msgstr "crwdns94782:0crwdne94782:0" -#: core/doctype/file/utils.py:127 +#: core/doctype/file/utils.py:128 msgid "File '{0}' not found" msgstr "crwdns94786:0{0}crwdne94786:0" @@ -10314,6 +10342,10 @@ msgstr "crwdns95034:0crwdne95034:0" msgid "For example if you cancel and amend INV004 it will become a new document INV004-1. This helps you to keep track of each amendment." msgstr "crwdns110948:0crwdne110948:0" +#: public/js/frappe/utils/dashboard_utils.js:162 +msgid "For example:" +msgstr "crwdns142878:0crwdne142878:0" + #: printing/page/print_format_builder/print_format_builder.js:744 msgid "For example: If you want to include the document ID, use {0}" msgstr "crwdns95036:0{0}crwdne95036:0" @@ -10493,6 +10525,20 @@ msgstr "crwdns95122:0crwdne95122:0" msgid "Frappe Light" msgstr "crwdns95124:0crwdne95124:0" +#. Option for the 'Service' (Select) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json email/frappemail.py:91 +msgid "Frappe Mail" +msgstr "crwdns142880:0crwdne142880:0" + +#: email/doctype/email_account/email_account.py:538 +msgid "Frappe Mail OAuth Error" +msgstr "crwdns142882:0crwdne142882:0" + +#. Label of the frappe_mail_site (Data) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json +msgid "Frappe Mail Site" +msgstr "crwdns142884:0crwdne142884:0" + #. Label of a standard help item #. Type: Action #: hooks.py @@ -10610,7 +10656,7 @@ msgstr "crwdns95188:0crwdne95188:0" msgid "Function Based On" msgstr "crwdns95192:0crwdne95192:0" -#: __init__.py:934 +#: __init__.py:940 msgid "Function {0} is not whitelisted." msgstr "crwdns95194:0{0}crwdne95194:0" @@ -10697,7 +10743,7 @@ msgstr "crwdns95228:0crwdne95228:0" msgid "Geolocation" msgstr "crwdns129450:0crwdne129450:0" -#: email/doctype/notification/notification.js:170 +#: email/doctype/notification/notification.js:193 msgid "Get Alerts for Today" msgstr "crwdns95236:0crwdne95236:0" @@ -11522,7 +11568,7 @@ msgstr "crwdns129578:0crwdne129578:0" msgid "Hide Standard Menu" msgstr "crwdns129580:0crwdne129580:0" -#: public/js/frappe/list/list_view.js:1611 +#: public/js/frappe/list/list_view.js:1665 msgid "Hide Tags" msgstr "crwdns95620:0crwdne95620:0" @@ -11540,7 +11586,7 @@ msgstr "crwdns95624:0crwdne95624:0" msgid "Hide descendant records of For Value." msgstr "crwdns129582:0crwdne129582:0" -#: public/js/frappe/form/layout.js:268 +#: public/js/frappe/form/layout.js:270 msgid "Hide details" msgstr "crwdns95628:0crwdne95628:0" @@ -11643,11 +11689,11 @@ msgstr "crwdns129602:0crwdne129602:0" #: core/doctype/data_import/importer.py:1139 #: core/doctype/data_import/importer.py:1204 #: core/doctype/data_import/importer.py:1207 desk/report/todo/todo.py:36 -#: model/meta.py:45 public/js/frappe/data_import/data_exporter.js:329 -#: public/js/frappe/data_import/data_exporter.js:344 +#: model/meta.py:45 public/js/frappe/data_import/data_exporter.js:330 +#: public/js/frappe/data_import/data_exporter.js:345 #: public/js/frappe/list/list_settings.js:334 -#: public/js/frappe/list/list_view.js:358 -#: public/js/frappe/list/list_view.js:422 public/js/frappe/model/meta.js:197 +#: public/js/frappe/list/list_view.js:355 +#: public/js/frappe/list/list_view.js:419 public/js/frappe/model/meta.js:197 #: public/js/frappe/model/model.js:122 msgid "ID" msgstr "crwdns95674:0crwdne95674:0" @@ -12041,7 +12087,7 @@ msgstr "crwdns95852:0crwdne95852:0" msgid "Image field must be of type Attach Image" msgstr "crwdns95854:0crwdne95854:0" -#: core/doctype/file/utils.py:135 +#: core/doctype/file/utils.py:136 msgid "Image link '{0}' is not valid" msgstr "crwdns95856:0{0}crwdne95856:0" @@ -12049,6 +12095,10 @@ msgstr "crwdns95856:0{0}crwdne95856:0" msgid "Image optimized" msgstr "crwdns95858:0crwdne95858:0" +#: core/doctype/file/utils.py:283 +msgid "Image: Corrupted Data Stream" +msgstr "crwdns142912:0crwdne142912:0" + #: public/js/frappe/views/image/image_view.js:13 msgid "Images" msgstr "crwdns95860:0crwdne95860:0" @@ -12087,7 +12137,7 @@ msgstr "crwdns129692:0crwdne129692:0" msgid "Import" msgstr "crwdns95866:0crwdne95866:0" -#: public/js/frappe/list/list_view.js:1673 +#: public/js/frappe/list/list_view.js:1727 msgctxt "Button in list view menu" msgid "Import" msgstr "crwdns95868:0crwdne95868:0" @@ -12336,8 +12386,8 @@ msgstr "crwdns95984:0crwdne95984:0" #. Label of the incoming_popimap_tab (Tab Break) field in DocType 'Email #. Account' #: email/doctype/email_account/email_account.json -msgid "Incoming (POP/IMAP)" -msgstr "crwdns129734:0crwdne129734:0" +msgid "Incoming" +msgstr "crwdns142886:0crwdne142886:0" #. Label of the mailbox_settings (Section Break) field in DocType 'Email #. Account' @@ -12676,7 +12726,7 @@ msgid "Invalid" msgstr "crwdns129784:0crwdne129784:0" #: public/js/form_builder/utils.js:221 public/js/frappe/form/grid_row.js:770 -#: public/js/frappe/form/layout.js:793 +#: public/js/frappe/form/layout.js:795 msgid "Invalid \"depends_on\" expression" msgstr "crwdns96130:0crwdne96130:0" @@ -12780,7 +12830,7 @@ msgstr "crwdns127664:0crwdne127664:0" msgid "Invalid Parameters." msgstr "crwdns96176:0crwdne96176:0" -#: core/doctype/user/user.py:1176 www/update-password.html:121 +#: core/doctype/user/user.py:1191 www/update-password.html:121 #: www/update-password.html:142 www/update-password.html:144 #: www/update-password.html:245 msgid "Invalid Password" @@ -13149,7 +13199,7 @@ msgstr "crwdns129846:0crwdne129846:0" msgid "Is Virtual" msgstr "crwdns129848:0crwdne129848:0" -#: core/doctype/file/utils.py:156 utils/file_manager.py:311 +#: core/doctype/file/utils.py:157 utils/file_manager.py:311 msgid "It is risky to delete this file: {0}. Please contact your System Manager." msgstr "crwdns96366:0{0}crwdne96366:0" @@ -13656,7 +13706,7 @@ msgstr "crwdns129948:0crwdne129948:0" msgid "Last Login" msgstr "crwdns129950:0crwdne129950:0" -#: email/doctype/notification/notification.js:31 +#: email/doctype/notification/notification.js:34 msgid "Last Modified Date" msgstr "crwdns110984:0crwdne110984:0" @@ -13704,6 +13754,11 @@ msgstr "crwdns129960:0crwdne129960:0" msgid "Last Sync On" msgstr "crwdns129962:0crwdne129962:0" +#. Label of the last_synced_at (Datetime) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json +msgid "Last Synced At" +msgstr "crwdns142888:0crwdne142888:0" + #. Label of the last_synced_on (Datetime) field in DocType 'Dashboard Chart' #: desk/doctype/dashboard_chart/dashboard_chart.json msgid "Last Synced On" @@ -13734,7 +13789,7 @@ msgstr "crwdns129968:0crwdne129968:0" msgid "Last Year" msgstr "crwdns129970:0crwdne129970:0" -#: public/js/frappe/widgets/chart_widget.js:698 +#: public/js/frappe/widgets/chart_widget.js:701 msgid "Last synced {0}" msgstr "crwdns96636:0{0}crwdne96636:0" @@ -13786,7 +13841,7 @@ msgid "Leave blank to repeat always" msgstr "crwdns129972:0crwdne129972:0" #: core/doctype/communication/mixins.py:207 -#: email/doctype/email_account/email_account.py:663 +#: email/doctype/email_account/email_account.py:714 msgid "Leave this conversation" msgstr "crwdns96658:0crwdne96658:0" @@ -13845,7 +13900,7 @@ msgstr "crwdns96684:0crwdne96684:0" msgid "Length of {0} should be between 1 and 1000" msgstr "crwdns96686:0{0}crwdne96686:0" -#: public/js/frappe/widgets/chart_widget.js:674 +#: public/js/frappe/widgets/chart_widget.js:677 msgid "Less" msgstr "crwdns110986:0crwdne110986:0" @@ -13928,6 +13983,7 @@ msgstr "crwdns129994:0crwdne129994:0" #. Label of the level (Select) field in DocType 'Help Article' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json +#: core/page/permission_manager/permission_manager.js:137 #: core/page/permission_manager/permission_manager.js:213 #: public/js/frappe/roles_editor.js:66 #: website/doctype/help_article/help_article.json @@ -14230,7 +14286,7 @@ msgstr "crwdns130058:0crwdne130058:0" msgid "List Settings" msgstr "crwdns130060:0crwdne130060:0" -#: public/js/frappe/list/list_view.js:1753 +#: public/js/frappe/list/list_view.js:1807 msgctxt "Button in list view menu" msgid "List Settings" msgstr "crwdns96868:0crwdne96868:0" @@ -14281,7 +14337,7 @@ msgstr "crwdns130066:0crwdne130066:0" msgid "Load More" msgstr "crwdns96888:0crwdne96888:0" -#: public/js/frappe/form/footer/form_timeline.js:214 +#: public/js/frappe/form/footer/form_timeline.js:216 msgctxt "Form timeline" msgid "Load More Communications" msgstr "crwdns96890:0crwdne96890:0" @@ -14290,7 +14346,7 @@ msgstr "crwdns96890:0crwdne96890:0" #: public/js/frappe/form/controls/multicheck.js:13 #: public/js/frappe/form/linked_with.js:13 #: public/js/frappe/list/base_list.js:498 -#: public/js/frappe/list/list_view.js:335 public/js/frappe/ui/listing.html:16 +#: public/js/frappe/list/list_view.js:332 public/js/frappe/ui/listing.html:16 #: public/js/frappe/views/reports/query_report.js:1017 msgid "Loading" msgstr "crwdns96892:0crwdne96892:0" @@ -14401,7 +14457,7 @@ msgstr "crwdns130080:0crwdne130080:0" msgid "Login Failed please try again" msgstr "crwdns96932:0crwdne96932:0" -#: email/doctype/email_account/email_account.py:141 +#: email/doctype/email_account/email_account.py:140 msgid "Login Id is required" msgstr "crwdns96934:0crwdne96934:0" @@ -14971,7 +15027,7 @@ msgstr "crwdns97172:0crwdne97172:0" msgid "Message" msgstr "crwdns97174:0crwdne97174:0" -#: __init__.py:618 public/js/frappe/ui/messages.js:265 +#: __init__.py:624 public/js/frappe/ui/messages.js:267 msgctxt "Default title of the message dialog" msgid "Message" msgstr "crwdns97184:0crwdne97184:0" @@ -15012,7 +15068,7 @@ msgstr "crwdns130188:0crwdne130188:0" msgid "Message clipped" msgstr "crwdns97214:0crwdne97214:0" -#: email/doctype/email_account/email_account.py:317 +#: email/doctype/email_account/email_account.py:333 msgid "Message from server: {0}" msgstr "crwdns97216:0{0}crwdne97216:0" @@ -15091,7 +15147,7 @@ msgstr "crwdns97252:0crwdne97252:0" msgid "Method" msgstr "crwdns130200:0crwdne130200:0" -#: __init__.py:936 +#: __init__.py:942 msgid "Method Not Allowed" msgstr "crwdns142858:0crwdne142858:0" @@ -15320,7 +15376,7 @@ msgstr "crwdns97390:0crwdne97390:0" msgid "Module to Export" msgstr "crwdns97392:0crwdne97392:0" -#: modules/utils.py:268 +#: modules/utils.py:272 msgid "Module {} not found" msgstr "crwdns97394:0crwdne97394:0" @@ -15404,7 +15460,7 @@ msgstr "crwdns111008:0crwdne111008:0" #: public/js/frappe/form/multi_select_dialog.js:72 #: public/js/frappe/ui/toolbar/search.js:285 #: public/js/frappe/ui/toolbar/search.js:300 -#: public/js/frappe/widgets/chart_widget.js:674 +#: public/js/frappe/widgets/chart_widget.js:677 #: templates/includes/list/list.html:23 #: templates/includes/search_template.html:13 msgid "More" @@ -15688,12 +15744,12 @@ msgstr "crwdns130266:0crwdne130266:0" msgid "Navigate Home" msgstr "crwdns97562:0crwdne97562:0" -#: public/js/frappe/list/list_view.js:1161 +#: public/js/frappe/list/list_view.js:1198 msgctxt "Description of a list view shortcut" msgid "Navigate list down" msgstr "crwdns97564:0crwdne97564:0" -#: public/js/frappe/list/list_view.js:1168 +#: public/js/frappe/list/list_view.js:1205 msgctxt "Description of a list view shortcut" msgid "Navigate list up" msgstr "crwdns97566:0crwdne97566:0" @@ -15777,11 +15833,11 @@ msgstr "crwdns97594:0crwdne97594:0" msgid "New Document Form" msgstr "crwdns130270:0crwdne130270:0" -#: desk/doctype/notification_log/notification_log.py:158 +#: desk/doctype/notification_log/notification_log.py:159 msgid "New Document Shared {0}" msgstr "crwdns97598:0{0}crwdne97598:0" -#: public/js/frappe/form/footer/form_timeline.js:26 +#: public/js/frappe/form/footer/form_timeline.js:27 #: public/js/frappe/views/communication.js:23 msgid "New Email" msgstr "crwdns97600:0crwdne97600:0" @@ -15791,7 +15847,7 @@ msgstr "crwdns97600:0crwdne97600:0" msgid "New Email Account" msgstr "crwdns97602:0crwdne97602:0" -#: public/js/frappe/form/footer/form_timeline.js:45 +#: public/js/frappe/form/footer/form_timeline.js:47 msgid "New Event" msgstr "crwdns97604:0crwdne97604:0" @@ -15807,7 +15863,7 @@ msgstr "crwdns97608:0crwdne97608:0" msgid "New Links" msgstr "crwdns111020:0crwdne111020:0" -#: desk/doctype/notification_log/notification_log.py:156 +#: desk/doctype/notification_log/notification_log.py:157 msgid "New Mention on {0}" msgstr "crwdns97610:0{0}crwdne97610:0" @@ -15825,7 +15881,7 @@ msgstr "crwdns97614:0crwdne97614:0" msgid "New Newsletter" msgstr "crwdns97618:0crwdne97618:0" -#: desk/doctype/notification_log/notification_log.py:155 +#: desk/doctype/notification_log/notification_log.py:156 msgid "New Notification" msgstr "crwdns97620:0crwdne97620:0" @@ -15930,7 +15986,7 @@ msgstr "crwdns97648:0{0}crwdnd97648:0{1}crwdne97648:0" msgid "New {} releases for the following apps are available" msgstr "crwdns97650:0crwdne97650:0" -#: core/doctype/user/user.py:753 +#: core/doctype/user/user.py:768 msgid "Newly created user {0} has no roles enabled." msgstr "crwdns97652:0{0}crwdne97652:0" @@ -15981,7 +16037,7 @@ msgstr "crwdns97668:0crwdne97668:0" msgid "Newsletters" msgstr "crwdns97670:0crwdne97670:0" -#: public/js/frappe/form/form_tour.js:318 +#: public/js/frappe/form/form_tour.js:14 public/js/frappe/form/form_tour.js:324 #: public/js/frappe/web_form/web_form.js:91 #: public/js/onboarding_tours/onboarding_tours.js:15 #: public/js/onboarding_tours/onboarding_tours.js:240 @@ -16131,7 +16187,7 @@ msgstr "crwdns97722:0crwdne97722:0" msgid "No Entry for the User {0} found within LDAP!" msgstr "crwdns97724:0{0}crwdne97724:0" -#: public/js/frappe/widgets/chart_widget.js:366 +#: public/js/frappe/widgets/chart_widget.js:367 msgid "No Filters Set" msgstr "crwdns97726:0crwdne97726:0" @@ -16209,7 +16265,7 @@ msgstr "crwdns97750:0crwdne97750:0" msgid "No Results found" msgstr "crwdns97752:0crwdne97752:0" -#: core/doctype/user/user.py:754 +#: core/doctype/user/user.py:769 msgid "No Roles Specified" msgstr "crwdns97754:0crwdne97754:0" @@ -16237,7 +16293,7 @@ msgstr "crwdns111056:0crwdne111056:0" msgid "No address added yet." msgstr "crwdns111058:0crwdne111058:0" -#: email/doctype/notification/notification.js:180 +#: email/doctype/notification/notification.js:203 msgid "No alerts for today" msgstr "crwdns97760:0crwdne97760:0" @@ -16364,11 +16420,11 @@ msgstr "crwdns130300:0crwdne130300:0" msgid "No of Sent SMS" msgstr "crwdns130302:0crwdne130302:0" -#: __init__.py:1126 client.py:109 client.py:151 +#: __init__.py:1132 client.py:109 client.py:151 msgid "No permission for {0}" msgstr "crwdns97808:0{0}crwdne97808:0" -#: public/js/frappe/form/form.js:1137 +#: public/js/frappe/form/form.js:1141 msgctxt "{0} = verb, {1} = object" msgid "No permission to '{0}' {1}" msgstr "crwdns97810:0{0}crwdnd97810:0{1}crwdne97810:0" @@ -16393,7 +16449,7 @@ msgstr "crwdns97818:0{0}crwdne97818:0" msgid "No records tagged." msgstr "crwdns111072:0crwdne111072:0" -#: public/js/frappe/data_import/data_exporter.js:224 +#: public/js/frappe/data_import/data_exporter.js:225 msgid "No records will be exported" msgstr "crwdns97820:0crwdne97820:0" @@ -16417,7 +16473,7 @@ msgstr "crwdns111076:0{0}crwdne111076:0" msgid "No {0} found" msgstr "crwdns111078:0{0}crwdne111078:0" -#: public/js/frappe/list/list_view.js:469 +#: public/js/frappe/list/list_view.js:466 msgid "No {0} found with matching filters. Clear filters to see all {0}." msgstr "crwdns97826:0{0}crwdnd97826:0{0}crwdne97826:0" @@ -16459,7 +16515,7 @@ msgstr "crwdns130308:0crwdne130308:0" msgid "Normalized Query" msgstr "crwdns130310:0crwdne130310:0" -#: core/doctype/user/user.py:959 templates/includes/login/login.js:257 +#: core/doctype/user/user.py:974 templates/includes/login/login.js:257 #: utils/oauth.py:265 msgid "Not Allowed" msgstr "crwdns97846:0crwdne97846:0" @@ -16506,7 +16562,7 @@ msgstr "crwdns97862:0crwdne97862:0" msgid "Not Nullable" msgstr "crwdns130314:0crwdne130314:0" -#: __init__.py:1018 app.py:357 desk/calendar.py:26 geo/utils.py:97 +#: __init__.py:1024 app.py:357 desk/calendar.py:26 geo/utils.py:97 #: public/js/frappe/web_form/webform_script.js:15 #: website/doctype/web_form/web_form.py:602 #: website/page_renderers/not_permitted_page.py:20 www/login.py:181 @@ -16558,7 +16614,7 @@ msgstr "crwdns97884:0crwdne97884:0" msgid "Not a valid Comma Separated Value (CSV File)" msgstr "crwdns97886:0crwdne97886:0" -#: core/doctype/user/user.py:235 +#: core/doctype/user/user.py:240 msgid "Not a valid User Image." msgstr "crwdns97888:0crwdne97888:0" @@ -16578,7 +16634,7 @@ msgstr "crwdns97892:0crwdne97892:0" msgid "Not allowed for {0}: {1}" msgstr "crwdns97894:0{0}crwdnd97894:0{1}crwdne97894:0" -#: email/doctype/notification/notification.py:392 +#: email/doctype/notification/notification.py:440 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "crwdns97896:0{0}crwdnd97896:0{0}crwdne97896:0" @@ -16760,6 +16816,18 @@ msgstr "crwdns97970:0crwdne97970:0" msgid "Notification sent to" msgstr "crwdns111084:0crwdne111084:0" +#: email/doctype/notification/notification.py:345 +msgid "Notification: customer {0} has no Mobile number set" +msgstr "crwdns142914:0{0}crwdne142914:0" + +#: email/doctype/notification/notification.py:331 +msgid "Notification: document {0} has no {1} number set (field: {2})" +msgstr "crwdns142916:0{0}crwdnd142916:0{1}crwdnd142916:0{2}crwdne142916:0" + +#: email/doctype/notification/notification.py:340 +msgid "Notification: user {0} has no Mobile number set" +msgstr "crwdns142918:0{0}crwdne142918:0" + #. Label of the notifications (Check) field in DocType 'Role' #: core/doctype/role/role.json #: public/js/frappe/ui/notifications/notifications.js:50 @@ -16964,7 +17032,7 @@ msgstr "crwdns98046:0crwdne98046:0" msgid "OAuth Scope" msgstr "crwdns98048:0crwdne98048:0" -#: email/doctype/email_account/email_account.js:182 +#: email/doctype/email_account/email_account.js:211 msgid "OAuth has been enabled but not authorised. Please use \"Authorise API Access\" button to do the same." msgstr "crwdns98050:0crwdne98050:0" @@ -16988,11 +17056,11 @@ msgstr "crwdns130366:0crwdne130366:0" msgid "OTP Issuer Name" msgstr "crwdns130368:0crwdne130368:0" -#: twofactor.py:461 +#: twofactor.py:445 msgid "OTP Secret Reset - {0}" msgstr "crwdns98060:0{0}crwdne98060:0" -#: twofactor.py:480 +#: twofactor.py:464 msgid "OTP Secret has been reset. Re-registration will be required on next login." msgstr "crwdns98062:0crwdne98062:0" @@ -17164,7 +17232,7 @@ msgstr "crwdns98110:0{0}crwdnd98110:0{1}crwdne98110:0" msgid "Only 200 inserts allowed in one request" msgstr "crwdns98112:0crwdne98112:0" -#: email/doctype/email_queue/email_queue.py:81 +#: email/doctype/email_queue/email_queue.py:82 msgid "Only Administrator can delete Email Queue" msgstr "crwdns98114:0crwdne98114:0" @@ -17328,7 +17396,7 @@ msgstr "crwdns130420:0crwdne130420:0" msgid "Open a module or tool" msgstr "crwdns98184:0crwdne98184:0" -#: public/js/frappe/list/list_view.js:1214 +#: public/js/frappe/list/list_view.js:1251 msgctxt "Description of a list view shortcut" msgid "Open list item" msgstr "crwdns98186:0crwdne98186:0" @@ -17503,10 +17571,10 @@ msgstr "crwdns111108:0crwdne111108:0" msgid "Other" msgstr "crwdns130444:0crwdne130444:0" -#. Label of the outgoing_smtp_tab (Tab Break) field in DocType 'Email Account' +#. Label of the outgoing_tab (Tab Break) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -msgid "Outgoing (SMTP)" -msgstr "crwdns130446:0crwdne130446:0" +msgid "Outgoing" +msgstr "crwdns142890:0crwdne142890:0" #. Label of the outgoing_mail_settings (Section Break) field in DocType 'Email #. Account' @@ -17921,11 +17989,11 @@ msgstr "crwdns130516:0crwdne130516:0" msgid "Password" msgstr "crwdns98434:0crwdne98434:0" -#: core/doctype/user/user.py:1022 +#: core/doctype/user/user.py:1037 msgid "Password Email Sent" msgstr "crwdns98448:0crwdne98448:0" -#: core/doctype/user/user.py:406 +#: core/doctype/user/user.py:412 msgid "Password Reset" msgstr "crwdns98450:0crwdne98450:0" @@ -17947,7 +18015,7 @@ msgstr "crwdns98456:0crwdne98456:0" msgid "Password for Base DN" msgstr "crwdns130520:0crwdne130520:0" -#: email/doctype/email_account/email_account.py:172 +#: email/doctype/email_account/email_account.py:182 msgid "Password is required or select Awaiting Password" msgstr "crwdns98460:0crwdne98460:0" @@ -17959,7 +18027,7 @@ msgstr "crwdns98462:0crwdne98462:0" msgid "Password not found for {0} {1} {2}" msgstr "crwdns98464:0{0}crwdnd98464:0{1}crwdnd98464:0{2}crwdne98464:0" -#: core/doctype/user/user.py:1021 +#: core/doctype/user/user.py:1036 msgid "Password reset instructions have been sent to {}'s email" msgstr "crwdns142862:0crwdne142862:0" @@ -17971,7 +18039,7 @@ msgstr "crwdns98468:0crwdne98468:0" msgid "Password size exceeded the maximum allowed size" msgstr "crwdns98470:0crwdne98470:0" -#: core/doctype/user/user.py:817 +#: core/doctype/user/user.py:832 msgid "Password size exceeded the maximum allowed size." msgstr "crwdns98472:0crwdne98472:0" @@ -18109,15 +18177,15 @@ msgstr "crwdns130548:0crwdne130548:0" msgid "Permanent" msgstr "crwdns130550:0crwdne130550:0" -#: public/js/frappe/form/form.js:1023 +#: public/js/frappe/form/form.js:1027 msgid "Permanently Cancel {0}?" msgstr "crwdns98534:0{0}crwdne98534:0" -#: public/js/frappe/form/form.js:1069 +#: public/js/frappe/form/form.js:1073 msgid "Permanently Discard {0}?" msgstr "crwdns127706:0{0}crwdne127706:0" -#: public/js/frappe/form/form.js:853 +#: public/js/frappe/form/form.js:857 msgid "Permanently Submit {0}?" msgstr "crwdns98536:0{0}crwdne98536:0" @@ -18304,6 +18372,10 @@ msgstr "crwdns130572:0crwdne130572:0" msgid "Plant" msgstr "crwdns130574:0crwdne130574:0" +#: email/doctype/email_account/email_account.py:535 +msgid "Please Authorize OAuth for Email Account {0}" +msgstr "crwdns142892:0{0}crwdne142892:0" + #: email/oauth.py:29 msgid "Please Authorize OAuth for Email Account {}" msgstr "crwdns98622:0crwdne98622:0" @@ -18332,7 +18404,7 @@ msgstr "crwdns98632:0crwdne98632:0" msgid "Please add a valid comment." msgstr "crwdns98634:0crwdne98634:0" -#: core/doctype/user/user.py:1004 +#: core/doctype/user/user.py:1019 msgid "Please ask your administrator to verify your sign-up" msgstr "crwdns98636:0crwdne98636:0" @@ -18364,7 +18436,7 @@ msgstr "crwdns98648:0crwdne98648:0" msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "crwdns98650:0{0}crwdne98650:0" -#: core/doctype/user/user.py:1002 +#: core/doctype/user/user.py:1017 msgid "Please check your email for verification" msgstr "crwdns98652:0crwdne98652:0" @@ -18646,11 +18718,11 @@ msgstr "crwdns98782:0crwdne98782:0" msgid "Please setup a message first" msgstr "crwdns98784:0crwdne98784:0" -#: email/doctype/email_account/email_account.py:407 +#: email/doctype/email_account/email_account.py:423 msgid "Please setup default Email Account from Settings > Email Account" msgstr "crwdns98786:0crwdne98786:0" -#: core/doctype/user/user.py:371 +#: core/doctype/user/user.py:377 msgid "Please setup default outgoing Email Account from Settings > Email Account" msgstr "crwdns98788:0crwdne98788:0" @@ -18931,6 +19003,7 @@ msgstr "crwdns130614:0crwdne130614:0" msgid "Preview:" msgstr "crwdns111132:0crwdne111132:0" +#: public/js/frappe/form/form_tour.js:15 #: public/js/frappe/web_form/web_form.js:95 #: public/js/onboarding_tours/onboarding_tours.js:16 #: templates/includes/slideshow.html:34 @@ -18952,7 +19025,7 @@ msgstr "crwdns98914:0crwdne98914:0" msgid "Previous Hash" msgstr "crwdns130616:0crwdne130616:0" -#: public/js/frappe/form/form.js:2217 +#: public/js/frappe/form/form.js:2222 msgid "Previous Submission" msgstr "crwdns98918:0crwdne98918:0" @@ -18992,9 +19065,11 @@ msgstr "crwdns112704:0{0}crwdne112704:0" #. Label of the print (Check) field in DocType 'Custom DocPerm' #. Label of the print (Check) field in DocType 'DocPerm' +#. Label of the print (Check) field in DocType 'User Document Type' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json #: core/doctype/success_action/success_action.js:56 +#: core/doctype/user_document_type/user_document_type.json #: printing/page/print/print.js:65 public/js/frappe/form/success_action.js:81 #: public/js/frappe/form/templates/print_layout.html:46 #: public/js/frappe/form/toolbar.js:332 public/js/frappe/form/toolbar.js:344 @@ -19005,7 +19080,7 @@ msgstr "crwdns112704:0{0}crwdne112704:0" msgid "Print" msgstr "crwdns98924:0crwdne98924:0" -#: public/js/frappe/list/list_view.js:1918 +#: public/js/frappe/list/list_view.js:1972 msgctxt "Button in list view actions menu" msgid "Print" msgstr "crwdns98926:0crwdne98926:0" @@ -19265,7 +19340,7 @@ msgstr "crwdns99052:0crwdne99052:0" msgid "Processing" msgstr "crwdns99054:0crwdne99054:0" -#: email/doctype/email_queue/email_queue.py:434 +#: email/doctype/email_queue/email_queue.py:447 msgid "Processing..." msgstr "crwdns99056:0crwdne99056:0" @@ -19401,7 +19476,7 @@ msgstr "crwdns99120:0crwdne99120:0" msgid "Publishing Dates" msgstr "crwdns130668:0crwdne130668:0" -#: email/doctype/email_account/email_account.js:159 +#: email/doctype/email_account/email_account.js:179 msgid "Pull Emails" msgstr "crwdns99124:0crwdne99124:0" @@ -19748,12 +19823,12 @@ msgstr "crwdns111152:0crwdne111152:0" msgid "Re-Run in Console" msgstr "crwdns99268:0crwdne99268:0" -#: email/doctype/email_account/email_account.py:669 +#: email/doctype/email_account/email_account.py:720 msgid "Re:" msgstr "crwdns99270:0crwdne99270:0" #: core/doctype/communication/communication.js:268 -#: public/js/frappe/form/footer/form_timeline.js:587 +#: public/js/frappe/form/footer/form_timeline.js:589 #: public/js/frappe/views/communication.js:355 msgid "Re: {0}" msgstr "crwdns99272:0{0}crwdne99272:0" @@ -20216,12 +20291,12 @@ msgid "Referrer" msgstr "crwdns99526:0crwdne99526:0" #: printing/page/print/print.js:73 public/js/frappe/desk.js:134 -#: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1196 +#: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1200 #: public/js/frappe/form/templates/print_layout.html:6 #: public/js/frappe/list/base_list.js:66 #: public/js/frappe/views/reports/query_report.js:1629 #: public/js/frappe/views/treeview.js:475 -#: public/js/frappe/widgets/chart_widget.js:290 +#: public/js/frappe/widgets/chart_widget.js:291 #: public/js/frappe/widgets/number_card_widget.js:324 msgid "Refresh" msgstr "crwdns99530:0crwdne99530:0" @@ -20248,7 +20323,7 @@ msgstr "crwdns130796:0crwdne130796:0" msgid "Refresh Token" msgstr "crwdns130798:0crwdne130798:0" -#: public/js/frappe/list/list_view.js:507 +#: public/js/frappe/list/list_view.js:504 msgctxt "Document count in list view" msgid "Refreshing" msgstr "crwdns111160:0crwdne111160:0" @@ -20258,7 +20333,7 @@ msgstr "crwdns111160:0crwdne111160:0" msgid "Refreshing..." msgstr "crwdns99546:0crwdne99546:0" -#: core/doctype/user/user.py:966 +#: core/doctype/user/user.py:981 msgid "Registered but disabled" msgstr "crwdns99548:0crwdne99548:0" @@ -20475,7 +20550,7 @@ msgstr "crwdns130826:0crwdne130826:0" #. Label of the reply (Text Editor) field in DocType 'Discussion Reply' #: core/doctype/communication/communication.js:57 -#: public/js/frappe/form/footer/form_timeline.js:550 +#: public/js/frappe/form/footer/form_timeline.js:552 #: website/doctype/discussion_reply/discussion_reply.json msgid "Reply" msgstr "crwdns99638:0crwdne99638:0" @@ -20801,7 +20876,7 @@ msgstr "crwdns99794:0crwdne99794:0" msgid "Reset Changes" msgstr "crwdns99796:0crwdne99796:0" -#: public/js/frappe/widgets/chart_widget.js:305 +#: public/js/frappe/widgets/chart_widget.js:306 msgid "Reset Chart" msgstr "crwdns99798:0crwdne99798:0" @@ -21149,7 +21224,7 @@ msgstr "crwdns99964:0crwdne99964:0" msgid "Role Permissions Manager" msgstr "crwdns99968:0crwdne99968:0" -#: public/js/frappe/list/list_view.js:1695 +#: public/js/frappe/list/list_view.js:1749 msgctxt "Button in list view menu" msgid "Role Permissions Manager" msgstr "crwdns99970:0crwdne99970:0" @@ -21181,7 +21256,7 @@ msgstr "crwdns130912:0crwdne130912:0" msgid "Role and Level" msgstr "crwdns130914:0crwdne130914:0" -#: core/doctype/user/user.py:316 +#: core/doctype/user/user.py:322 msgid "Role has been set as per the user type {0}" msgstr "crwdns99982:0{0}crwdne99982:0" @@ -21482,7 +21557,7 @@ msgstr "crwdns100122:0{0}crwdne100122:0" msgid "SMS was not sent. Please contact Administrator." msgstr "crwdns111190:0crwdne111190:0" -#: email/doctype/email_account/email_account.py:189 +#: email/doctype/email_account/email_account.py:205 msgid "SMTP Server is required" msgstr "crwdns100124:0crwdne100124:0" @@ -21580,7 +21655,7 @@ msgstr "crwdns130978:0crwdne130978:0" #: email/doctype/notification/notification.json #: printing/page/print/print.js:856 #: printing/page/print_format_builder/print_format_builder.js:160 -#: public/js/frappe/form/footer/form_timeline.js:661 +#: public/js/frappe/form/footer/form_timeline.js:663 #: public/js/frappe/form/quick_entry.js:161 #: public/js/frappe/list/list_settings.js:36 #: public/js/frappe/list/list_settings.js:244 @@ -21634,7 +21709,7 @@ msgstr "crwdns100184:0crwdne100184:0" msgid "Save on Completion" msgstr "crwdns130980:0crwdne130980:0" -#: public/js/frappe/form/form_tour.js:289 +#: public/js/frappe/form/form_tour.js:295 msgid "Save the document." msgstr "crwdns100188:0crwdne100188:0" @@ -21977,7 +22052,7 @@ msgstr "crwdns111200:0crwdne111200:0" msgid "See all past reports." msgstr "crwdns100338:0crwdne100338:0" -#: public/js/frappe/form/form.js:1230 +#: public/js/frappe/form/form.js:1234 #: website/doctype/contact_us_settings/contact_us_settings.js:4 msgid "See on Website" msgstr "crwdns100340:0crwdne100340:0" @@ -22036,7 +22111,7 @@ msgstr "crwdns131026:0crwdne131026:0" msgid "Select" msgstr "crwdns100362:0crwdne100362:0" -#: public/js/frappe/data_import/data_exporter.js:148 +#: public/js/frappe/data_import/data_exporter.js:149 #: public/js/frappe/form/controls/multicheck.js:166 msgid "Select All" msgstr "crwdns111204:0crwdne111204:0" @@ -22124,11 +22199,11 @@ msgstr "crwdns111208:0crwdne111208:0" msgid "Select Fields" msgstr "crwdns100414:0crwdne100414:0" -#: public/js/frappe/data_import/data_exporter.js:146 +#: public/js/frappe/data_import/data_exporter.js:147 msgid "Select Fields To Insert" msgstr "crwdns100416:0crwdne100416:0" -#: public/js/frappe/data_import/data_exporter.js:147 +#: public/js/frappe/data_import/data_exporter.js:148 msgid "Select Fields To Update" msgstr "crwdns100418:0crwdne100418:0" @@ -22161,7 +22236,7 @@ msgstr "crwdns100428:0crwdne100428:0" msgid "Select List View" msgstr "crwdns131034:0crwdne131034:0" -#: public/js/frappe/data_import/data_exporter.js:157 +#: public/js/frappe/data_import/data_exporter.js:158 msgid "Select Mandatory" msgstr "crwdns100432:0crwdne100432:0" @@ -22243,7 +22318,7 @@ msgstr "crwdns100466:0crwdne100466:0" msgid "Select a valid Subject field for creating documents from Email" msgstr "crwdns100468:0crwdne100468:0" -#: public/js/frappe/form/form_tour.js:315 +#: public/js/frappe/form/form_tour.js:321 msgid "Select an Image" msgstr "crwdns100470:0crwdne100470:0" @@ -22265,13 +22340,13 @@ msgstr "crwdns100474:0crwdne100474:0" msgid "Select atleast 2 actions" msgstr "crwdns100476:0crwdne100476:0" -#: public/js/frappe/list/list_view.js:1228 +#: public/js/frappe/list/list_view.js:1265 msgctxt "Description of a list view shortcut" msgid "Select list item" msgstr "crwdns100478:0crwdne100478:0" -#: public/js/frappe/list/list_view.js:1180 -#: public/js/frappe/list/list_view.js:1196 +#: public/js/frappe/list/list_view.js:1217 +#: public/js/frappe/list/list_view.js:1233 msgctxt "Description of a list view shortcut" msgid "Select multiple list items" msgstr "crwdns100480:0crwdne100480:0" @@ -22713,6 +22788,14 @@ msgstr "crwdns131134:0crwdne131134:0" msgid "Session Expiry must be in format {0}" msgstr "crwdns100684:0{0}crwdne100684:0" +#: desk/doctype/dashboard_chart/dashboard_chart.js:400 +#: desk/doctype/dashboard_chart/dashboard_chart.js:487 +#: desk/doctype/number_card/number_card.js:295 +#: desk/doctype/number_card/number_card.js:387 +#: public/js/frappe/widgets/chart_widget.js:407 +msgid "Set" +msgstr "crwdns142894:0crwdne142894:0" + #: public/js/frappe/ui/filters/filter.js:569 msgctxt "Field value is set" msgid "Set" @@ -22744,7 +22827,7 @@ msgstr "crwdns100694:0crwdne100694:0" msgid "Set Filters" msgstr "crwdns100696:0crwdne100696:0" -#: public/js/frappe/widgets/chart_widget.js:395 +#: public/js/frappe/widgets/chart_widget.js:396 #: public/js/frappe/widgets/quick_list_widget.js:104 msgid "Set Filters for {0}" msgstr "crwdns100698:0{0}crwdne100698:0" @@ -22833,6 +22916,10 @@ msgstr "crwdns100730:0crwdne100730:0" msgid "Set by user" msgstr "crwdns131150:0crwdne131150:0" +#: public/js/frappe/utils/dashboard_utils.js:162 +msgid "Set dynamic filter values in JavaScript for the required fields here." +msgstr "crwdns142896:0crwdne142896:0" + #. Description of the 'Precision' (Select) field in DocType 'DocField' #. Description of the 'Precision' (Select) field in DocType 'Custom Field' #. Description of the 'Precision' (Select) field in DocType 'Customize Form @@ -22988,9 +23075,11 @@ msgstr "crwdns131162:0crwdne131162:0" #. Label of the share (Check) field in DocType 'Custom DocPerm' #. Label of the share (Check) field in DocType 'DocPerm' #. Label of the share (Check) field in DocType 'DocShare' +#. Label of the share (Check) field in DocType 'User Document Type' #. Option for the 'Type' (Select) field in DocType 'Notification Log' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json core/doctype/docshare/docshare.json +#: core/doctype/user_document_type/user_document_type.json #: desk/doctype/notification_log/notification_log.json #: public/js/frappe/form/templates/form_sidebar.html:110 msgid "Share" @@ -23102,7 +23191,7 @@ msgstr "crwdns131180:0crwdne131180:0" msgid "Show Error" msgstr "crwdns100834:0crwdne100834:0" -#: public/js/frappe/form/layout.js:561 +#: public/js/frappe/form/layout.js:563 msgid "Show Fieldname (click to copy on clipboard)" msgstr "crwdns100838:0crwdne100838:0" @@ -23220,7 +23309,7 @@ msgid "Show Sidebar" msgstr "crwdns131206:0crwdne131206:0" #: public/js/frappe/list/list_sidebar.html:66 -#: public/js/frappe/list/list_view.js:1611 +#: public/js/frappe/list/list_view.js:1665 msgid "Show Tags" msgstr "crwdns100886:0crwdne100886:0" @@ -23267,7 +23356,7 @@ msgstr "crwdns131212:0crwdne131212:0" msgid "Show all Versions" msgstr "crwdns100904:0crwdne100904:0" -#: public/js/frappe/form/footer/form_timeline.js:67 +#: public/js/frappe/form/footer/form_timeline.js:69 msgid "Show all activity" msgstr "crwdns111236:0crwdne111236:0" @@ -23307,7 +23396,7 @@ msgstr "crwdns131222:0crwdne131222:0" msgid "Show link to document" msgstr "crwdns131224:0crwdne131224:0" -#: public/js/frappe/form/layout.js:255 public/js/frappe/form/layout.js:273 +#: public/js/frappe/form/layout.js:257 public/js/frappe/form/layout.js:275 msgid "Show more details" msgstr "crwdns100920:0crwdne100920:0" @@ -23361,7 +23450,7 @@ msgstr "crwdns131236:0crwdne131236:0" msgid "Sign Up and Confirmation" msgstr "crwdns131238:0crwdne131238:0" -#: core/doctype/user/user.py:959 +#: core/doctype/user/user.py:974 msgid "Sign Up is disabled" msgstr "crwdns100938:0crwdne100938:0" @@ -23477,7 +23566,7 @@ msgstr "crwdns100986:0crwdne100986:0" msgid "Skipping column {0}" msgstr "crwdns100988:0{0}crwdne100988:0" -#: modules/utils.py:171 +#: modules/utils.py:175 msgid "Skipping fixture syncing for doctype {0} from file {1}" msgstr "crwdns100990:0{0}crwdnd100990:0{1}crwdne100990:0" @@ -23759,6 +23848,10 @@ msgstr "crwdns101110:0crwdne101110:0" msgid "Standard Not Set" msgstr "crwdns101112:0crwdne101112:0" +#: core/page/permission_manager/permission_manager.js:125 +msgid "Standard Permissions" +msgstr "crwdns142898:0crwdne142898:0" + #: printing/doctype/print_format/print_format.py:74 msgid "Standard Print Format cannot be updated" msgstr "crwdns101114:0crwdne101114:0" @@ -24161,7 +24254,7 @@ msgstr "crwdns101312:0crwdne101312:0" msgid "Submit" msgstr "crwdns101314:0crwdne101314:0" -#: public/js/frappe/list/list_view.js:1985 +#: public/js/frappe/list/list_view.js:2039 msgctxt "Button in list view actions menu" msgid "Submit" msgstr "crwdns101316:0crwdne101316:0" @@ -24214,11 +24307,11 @@ msgstr "crwdns131364:0crwdne131364:0" msgid "Submit this document to complete this step." msgstr "crwdns101344:0crwdne101344:0" -#: public/js/frappe/form/form.js:1216 +#: public/js/frappe/form/form.js:1220 msgid "Submit this document to confirm" msgstr "crwdns101346:0crwdne101346:0" -#: public/js/frappe/list/list_view.js:1990 +#: public/js/frappe/list/list_view.js:2044 msgctxt "Title of confirmation dialog" msgid "Submit {0} documents?" msgstr "crwdns101348:0{0}crwdne101348:0" @@ -24368,7 +24461,7 @@ msgstr "crwdns127884:0crwdne127884:0" msgid "Suggested Indexes" msgstr "crwdns131380:0crwdne131380:0" -#: core/doctype/user/user.py:674 +#: core/doctype/user/user.py:689 msgid "Suggested Username: {0}" msgstr "crwdns101420:0{0}crwdne101420:0" @@ -24891,7 +24984,7 @@ msgstr "crwdns131428:0crwdne131428:0" msgid "Templates" msgstr "crwdns101586:0crwdne101586:0" -#: core/doctype/user/user.py:970 +#: core/doctype/user/user.py:985 msgid "Temporarily Disabled" msgstr "crwdns101588:0crwdne101588:0" @@ -25041,7 +25134,11 @@ msgstr "crwdns101652:0{0}crwdnd101652:0{1}crwdnd101652:0{2}crwdne101652:0" msgid "The comment cannot be empty" msgstr "crwdns101654:0crwdne101654:0" -#: public/js/frappe/list/list_view.js:630 +#: templates/emails/workflow_action.html:9 +msgid "The contents of this email are strictly confidential. Please do not forward this email to anyone." +msgstr "crwdns142920:0crwdne142920:0" + +#: public/js/frappe/list/list_view.js:629 msgid "The count shown is an estimated count. Click here to see the accurate count." msgstr "crwdns111470:0crwdne111470:0" @@ -25140,11 +25237,11 @@ msgid "The project number obtained from Google Cloud Console under " msgstr "crwdns131456:0crwdne131456:0" -#: core/doctype/user/user.py:930 +#: core/doctype/user/user.py:945 msgid "The reset password link has been expired" msgstr "crwdns101696:0crwdne101696:0" -#: core/doctype/user/user.py:932 +#: core/doctype/user/user.py:947 msgid "The reset password link has either been used before or is invalid" msgstr "crwdns101698:0crwdne101698:0" @@ -25182,7 +25279,7 @@ msgstr "crwdns101710:0crwdne101710:0" msgid "The user from this field will be rewarded points" msgstr "crwdns131458:0crwdne131458:0" -#: public/js/frappe/form/controls/data.js:24 +#: public/js/frappe/form/controls/data.js:25 msgid "The value you pasted was {0} characters long. Max allowed characters is {1}." msgstr "crwdns101714:0{0}crwdnd101714:0{1}crwdne101714:0" @@ -25343,7 +25440,7 @@ msgstr "crwdns101774:0crwdne101774:0" msgid "This action is irreversible. Do you wish to continue?" msgstr "crwdns112746:0crwdne112746:0" -#: __init__.py:1014 +#: __init__.py:1020 msgid "This action is only allowed for {}" msgstr "crwdns101776:0crwdne101776:0" @@ -25389,11 +25486,11 @@ msgstr "crwdns101788:0crwdne101788:0" msgid "This document has been reverted" msgstr "crwdns101790:0crwdne101790:0" -#: public/js/frappe/form/form.js:1304 +#: public/js/frappe/form/form.js:1308 msgid "This document has unsaved changes which might not appear in final PDF.
    Consider saving the document before printing." msgstr "crwdns127762:0crwdne127762:0" -#: public/js/frappe/form/form.js:1097 +#: public/js/frappe/form/form.js:1101 msgid "This document is already amended, you cannot ammend it again" msgstr "crwdns101792:0crwdne101792:0" @@ -25427,7 +25524,7 @@ msgstr "crwdns131480:0crwdne131480:0" msgid "This file is public. It can be accessed without authentication." msgstr "crwdns101802:0crwdne101802:0" -#: public/js/frappe/form/form.js:1194 +#: public/js/frappe/form/form.js:1198 msgid "This form has been modified after you have loaded it" msgstr "crwdns101804:0crwdne101804:0" @@ -25574,7 +25671,7 @@ msgstr "crwdns101866:0crwdne101866:0" msgid "This will terminate the job immediately and might be dangerous, are you sure? " msgstr "crwdns101868:0crwdne101868:0" -#: core/doctype/user/user.py:1190 +#: core/doctype/user/user.py:1205 msgid "Throttled" msgstr "crwdns101870:0crwdne101870:0" @@ -25924,7 +26021,7 @@ msgstr "crwdns102052:0crwdne102052:0" msgid "To print output use print(text)" msgstr "crwdns131550:0crwdne131550:0" -#: core/doctype/user_type/user_type.py:295 +#: core/doctype/user_type/user_type.py:292 msgid "To set the role {0} in the user {1}, kindly set the {2} field as {3} in one of the {4} record." msgstr "crwdns102056:0{0}crwdnd102056:0{1}crwdnd102056:0{2}crwdnd102056:0{3}crwdnd102056:0{4}crwdne102056:0" @@ -25991,7 +26088,7 @@ msgstr "crwdns102084:0crwdne102084:0" msgid "Toggle Sidebar" msgstr "crwdns102086:0crwdne102086:0" -#: public/js/frappe/list/list_view.js:1726 +#: public/js/frappe/list/list_view.js:1780 msgctxt "Button in list view menu" msgid "Toggle Sidebar" msgstr "crwdns102088:0crwdne102088:0" @@ -26038,7 +26135,7 @@ msgstr "crwdns102108:0crwdne102108:0" msgid "Too many changes to database in single action." msgstr "crwdns102110:0crwdne102110:0" -#: core/doctype/user/user.py:971 +#: core/doctype/user/user.py:986 msgid "Too many users signed up recently, so the registration is disabled. Please try back in an hour" msgstr "crwdns102112:0crwdne102112:0" @@ -26541,7 +26638,7 @@ msgstr "crwdns102332:0{0}crwdne102332:0" msgid "Unable to open attached file. Did you export it as CSV?" msgstr "crwdns102334:0crwdne102334:0" -#: core/doctype/file/utils.py:97 core/doctype/file/utils.py:129 +#: core/doctype/file/utils.py:98 core/doctype/file/utils.py:130 msgid "Unable to read file format for {0}" msgstr "crwdns102336:0{0}crwdne102336:0" @@ -26650,7 +26747,7 @@ msgstr "crwdns131670:0crwdne131670:0" msgid "Unsafe SQL query" msgstr "crwdns102382:0crwdne102382:0" -#: public/js/frappe/data_import/data_exporter.js:158 +#: public/js/frappe/data_import/data_exporter.js:159 #: public/js/frappe/form/controls/multicheck.js:166 msgid "Unselect All" msgstr "crwdns111300:0crwdne111300:0" @@ -26820,7 +26917,7 @@ msgctxt "Freeze message while updating a document" msgid "Updating" msgstr "crwdns102458:0crwdne102458:0" -#: email/doctype/email_queue/email_queue.py:433 +#: email/doctype/email_queue/email_queue.py:446 msgid "Updating Email Queue Statuses. The emails will be picked up in the next scheduled run." msgstr "crwdns102460:0crwdne102460:0" @@ -27148,7 +27245,7 @@ msgstr "crwdns131746:0crwdne131746:0" msgid "User Id Field" msgstr "crwdns131748:0crwdne131748:0" -#: core/doctype/user_type/user_type.py:287 +#: core/doctype/user_type/user_type.py:284 msgid "User Id Field is mandatory in the user type {0}" msgstr "crwdns102618:0{0}crwdne102618:0" @@ -27178,7 +27275,7 @@ msgstr "crwdns102624:0crwdne102624:0" msgid "User Permissions" msgstr "crwdns102628:0crwdne102628:0" -#: public/js/frappe/list/list_view.js:1684 +#: public/js/frappe/list/list_view.js:1738 msgctxt "Button in list view menu" msgid "User Permissions" msgstr "crwdns102630:0crwdne102630:0" @@ -27285,7 +27382,7 @@ msgstr "crwdns102664:0crwdne102664:0" msgid "User must always select" msgstr "crwdns131762:0crwdne131762:0" -#: model/delete_doc.py:235 +#: model/delete_doc.py:244 msgid "User not allowed to delete {0}: {1}" msgstr "crwdns102668:0{0}crwdnd102668:0{1}crwdne102668:0" @@ -27301,15 +27398,15 @@ msgstr "crwdns102672:0{0}crwdne102672:0" msgid "User with email: {0} does not exist in the system. Please ask 'System Administrator' to create the user for you." msgstr "crwdns102674:0{0}crwdne102674:0" -#: core/doctype/user/user.py:485 +#: core/doctype/user/user.py:491 msgid "User {0} cannot be deleted" msgstr "crwdns102676:0{0}crwdne102676:0" -#: core/doctype/user/user.py:280 +#: core/doctype/user/user.py:285 msgid "User {0} cannot be disabled" msgstr "crwdns102678:0{0}crwdne102678:0" -#: core/doctype/user/user.py:556 +#: core/doctype/user/user.py:571 msgid "User {0} cannot be renamed" msgstr "crwdns102680:0{0}crwdne102680:0" @@ -27330,7 +27427,7 @@ msgstr "crwdns127898:0{0}crwdne127898:0" msgid "User {0} has requested for data deletion" msgstr "crwdns102686:0{0}crwdne102686:0" -#: core/doctype/user/user.py:1319 +#: core/doctype/user/user.py:1334 msgid "User {0} impersonated as {1}" msgstr "crwdns111442:0{0}crwdnd111442:0{1}crwdne111442:0" @@ -27358,7 +27455,7 @@ msgstr "crwdns131764:0crwdne131764:0" msgid "Username" msgstr "crwdns102694:0crwdne102694:0" -#: core/doctype/user/user.py:641 +#: core/doctype/user/user.py:656 msgid "Username {0} already exists" msgstr "crwdns102700:0{0}crwdne102700:0" @@ -27421,6 +27518,12 @@ msgstr "crwdns111316:0crwdne111316:0" msgid "Validate Field" msgstr "crwdns131774:0crwdne131774:0" +#. Label of the validate_frappe_mail_settings (Button) field in DocType 'Email +#. Account' +#: email/doctype/email_account/email_account.json +msgid "Validate Frappe Mail Settings" +msgstr "crwdns142900:0crwdne142900:0" + #. Label of the validate_ssl_certificate (Check) field in DocType 'Email #. Account' #. Label of the validate_ssl_certificate (Check) field in DocType 'Email @@ -27559,7 +27662,7 @@ msgstr "crwdns111318:0crwdne111318:0" msgid "Verdana" msgstr "crwdns131792:0crwdne131792:0" -#: twofactor.py:357 +#: twofactor.py:352 msgid "Verfication Code" msgstr "crwdns102780:0crwdne102780:0" @@ -27580,11 +27683,11 @@ msgstr "crwdns102784:0crwdne102784:0" msgid "Verified" msgstr "crwdns131794:0crwdne131794:0" -#: public/js/frappe/ui/messages.js:350 +#: public/js/frappe/ui/messages.js:352 msgid "Verify" msgstr "crwdns102788:0crwdne102788:0" -#: public/js/frappe/ui/messages.js:349 +#: public/js/frappe/ui/messages.js:351 msgid "Verify Password" msgstr "crwdns102790:0crwdne102790:0" @@ -27957,7 +28060,7 @@ msgstr "crwdns131842:0crwdne131842:0" #. Group in Module Def's connections #. Name of a Workspace #: core/doctype/module_def/module_def.json -#: email/doctype/newsletter/newsletter.py:449 +#: email/doctype/newsletter/newsletter.py:453 #: public/js/frappe/ui/toolbar/about.js:8 #: website/workspace/website/website.json msgid "Website" @@ -28195,11 +28298,11 @@ msgstr "crwdns131860:0crwdne131860:0" msgid "Welcome Workspace" msgstr "crwdns103062:0crwdne103062:0" -#: core/doctype/user/user.py:363 +#: core/doctype/user/user.py:369 msgid "Welcome email sent" msgstr "crwdns103064:0crwdne103064:0" -#: core/doctype/user/user.py:424 +#: core/doctype/user/user.py:430 msgid "Welcome to {0}" msgstr "crwdns103066:0{0}crwdne103066:0" @@ -28622,7 +28725,7 @@ msgctxt "Name of the current user. For example: You edited this 5 hours ago." msgid "You" msgstr "crwdns103252:0crwdne103252:0" -#: public/js/frappe/form/footer/form_timeline.js:462 +#: public/js/frappe/form/footer/form_timeline.js:464 msgid "You Liked" msgstr "crwdns103254:0crwdne103254:0" @@ -28686,7 +28789,7 @@ msgstr "crwdns103280:0crwdne103280:0" msgid "You are not permitted to access this page." msgstr "crwdns103282:0crwdne103282:0" -#: __init__.py:933 +#: __init__.py:939 msgid "You are not permitted to access this resource." msgstr "crwdns103284:0crwdne103284:0" @@ -28698,11 +28801,11 @@ msgstr "crwdns103286:0crwdne103286:0" msgid "You are only allowed to update order, do not remove or add apps." msgstr "crwdns103288:0crwdne103288:0" -#: email/doctype/email_account/email_account.js:216 +#: email/doctype/email_account/email_account.js:245 msgid "You are selecting Sync Option as ALL, It will resync all read as well as unread message from server. This may also cause the duplication of Communication (emails)." msgstr "crwdns103290:0crwdne103290:0" -#: public/js/frappe/form/footer/form_timeline.js:413 +#: public/js/frappe/form/footer/form_timeline.js:415 msgctxt "Form timeline" msgid "You attached {0}" msgstr "crwdns103292:0{0}crwdne103292:0" @@ -28739,9 +28842,9 @@ msgstr "crwdns103302:0{0}crwdne103302:0" msgid "You can continue with the onboarding after exploring this page" msgstr "crwdns103304:0crwdne103304:0" -#: core/doctype/user/user.py:543 -msgid "You can disable the user instead of deleting it." -msgstr "crwdns111478:0crwdne111478:0" +#: model/delete_doc.py:136 +msgid "You can disable this {0} instead of deleting it." +msgstr "crwdns142902:0{0}crwdne142902:0" #: core/doctype/file/file.py:691 msgid "You can increase the limit from System Settings." @@ -28833,12 +28936,12 @@ msgstr "crwdns103340:0{0}crwdne103340:0" msgid "You changed the values for {0} {1}" msgstr "crwdns103342:0{0}crwdnd103342:0{1}crwdne103342:0" -#: public/js/frappe/form/footer/form_timeline.js:442 +#: public/js/frappe/form/footer/form_timeline.js:444 msgctxt "Form timeline" msgid "You changed {0} to {1}" msgstr "crwdns103344:0{0}crwdnd103344:0{1}crwdne103344:0" -#: public/js/frappe/form/footer/form_timeline.js:138 +#: public/js/frappe/form/footer/form_timeline.js:140 #: public/js/frappe/form/sidebar/form_sidebar.js:106 msgid "You created this" msgstr "crwdns103346:0crwdne103346:0" @@ -28868,7 +28971,7 @@ msgstr "crwdns103356:0crwdne103356:0" msgid "You do not have permission to view this document" msgstr "crwdns103358:0crwdne103358:0" -#: public/js/frappe/form/form.js:955 +#: public/js/frappe/form/form.js:959 msgid "You do not have permissions to cancel all linked documents." msgstr "crwdns103360:0crwdne103360:0" @@ -28920,7 +29023,7 @@ msgstr "crwdns103382:0crwdne103382:0" msgid "You have received a ❤️ like on your blog post" msgstr "crwdns103384:0crwdne103384:0" -#: twofactor.py:448 +#: twofactor.py:432 msgid "You have to enable Two Factor Auth from System Settings." msgstr "crwdns103386:0crwdne103386:0" @@ -28940,7 +29043,7 @@ msgstr "crwdns103390:0{0}crwdne103390:0" msgid "You haven't added any Dashboard Charts or Number Cards yet." msgstr "crwdns111346:0crwdne111346:0" -#: public/js/frappe/list/list_view.js:473 +#: public/js/frappe/list/list_view.js:470 msgid "You haven't created a {0} yet" msgstr "crwdns103392:0{0}crwdne103392:0" @@ -28948,7 +29051,7 @@ msgstr "crwdns103392:0{0}crwdne103392:0" msgid "You hit the rate limit because of too many requests. Please try after sometime." msgstr "crwdns103394:0crwdne103394:0" -#: public/js/frappe/form/footer/form_timeline.js:149 +#: public/js/frappe/form/footer/form_timeline.js:151 #: public/js/frappe/form/sidebar/form_sidebar.js:95 msgid "You last edited this" msgstr "crwdns103396:0crwdne103396:0" @@ -29009,7 +29112,7 @@ msgstr "crwdns103418:0crwdne103418:0" msgid "You need to select indexes you want to add first." msgstr "crwdns127892:0crwdne127892:0" -#: email/doctype/email_account/email_account.py:147 +#: email/doctype/email_account/email_account.py:153 msgid "You need to set one IMAP folder for {0}" msgstr "crwdns103420:0{0}crwdne103420:0" @@ -29021,7 +29124,7 @@ msgstr "crwdns103422:0crwdne103422:0" msgid "You need {0} permission to fetch values from {1} {2}" msgstr "crwdns103424:0{0}crwdnd103424:0{1}crwdnd103424:0{2}crwdne103424:0" -#: public/js/frappe/form/footer/form_timeline.js:418 +#: public/js/frappe/form/footer/form_timeline.js:420 msgctxt "Form timeline" msgid "You removed attachment {0}" msgstr "crwdns103426:0{0}crwdne103426:0" @@ -29048,7 +29151,7 @@ msgstr "crwdns103434:0{0}crwdne103434:0" msgid "You unfollowed this document" msgstr "crwdns103436:0crwdne103436:0" -#: public/js/frappe/form/footer/form_timeline.js:182 +#: public/js/frappe/form/footer/form_timeline.js:184 msgid "You viewed this" msgstr "crwdns103438:0crwdne103438:0" @@ -29770,7 +29873,7 @@ msgstr "crwdns103962:0crwdne103962:0" msgid "text in document type" msgstr "crwdns103968:0crwdne103968:0" -#: public/js/frappe/form/controls/data.js:35 +#: public/js/frappe/form/controls/data.js:36 msgid "this form" msgstr "crwdns103980:0crwdne103980:0" @@ -29815,7 +29918,7 @@ msgstr "crwdns104008:0crwdne104008:0" msgid "via Google Meet" msgstr "crwdns132068:0crwdne132068:0" -#: email/doctype/notification/notification.py:216 +#: email/doctype/notification/notification.py:220 msgid "via Notification" msgstr "crwdns104012:0crwdne104012:0" @@ -29883,12 +29986,12 @@ msgstr "crwdns104048:0{0}crwdne104048:0" msgid "{0} ${type}" msgstr "crwdns104050:0{0}crwdnd104050:0${type}crwdne104050:0" -#: public/js/frappe/data_import/data_exporter.js:79 +#: public/js/frappe/data_import/data_exporter.js:80 #: public/js/frappe/views/gantt/gantt_view.js:54 msgid "{0} ({1})" msgstr "crwdns104052:0{0}crwdnd104052:0{1}crwdne104052:0" -#: public/js/frappe/data_import/data_exporter.js:76 +#: public/js/frappe/data_import/data_exporter.js:77 msgid "{0} ({1}) (1 row mandatory)" msgstr "crwdns104054:0{0}crwdnd104054:0{1}crwdne104054:0" @@ -29931,14 +30034,14 @@ msgstr "crwdns104068:0{0}crwdne104068:0" msgid "{0} Google Contacts synced." msgstr "crwdns104070:0{0}crwdne104070:0" -#: public/js/frappe/form/footer/form_timeline.js:463 +#: public/js/frappe/form/footer/form_timeline.js:465 msgid "{0} Liked" msgstr "crwdns104072:0{0}crwdne104072:0" #: public/js/frappe/ui/toolbar/search_utils.js:83 #: public/js/frappe/ui/toolbar/search_utils.js:84 #: public/js/frappe/utils/utils.js:924 -#: public/js/frappe/widgets/chart_widget.js:317 www/list.html:4 www/list.html:8 +#: public/js/frappe/widgets/chart_widget.js:318 www/list.html:4 www/list.html:8 msgid "{0} List" msgstr "crwdns104074:0{0}crwdne104074:0" @@ -29965,7 +30068,7 @@ msgstr "crwdns104084:0{0}crwdnd104084:0{1}crwdnd104084:0{2}crwdnd104084:0{3}crwd #: public/js/frappe/ui/toolbar/search_utils.js:95 #: public/js/frappe/ui/toolbar/search_utils.js:96 #: public/js/frappe/utils/utils.js:921 -#: public/js/frappe/widgets/chart_widget.js:325 +#: public/js/frappe/widgets/chart_widget.js:326 msgid "{0} Report" msgstr "crwdns104086:0{0}crwdne104086:0" @@ -29984,7 +30087,7 @@ msgstr "crwdns104088:0{0}crwdne104088:0" msgid "{0} Tree" msgstr "crwdns104090:0{0}crwdne104090:0" -#: public/js/frappe/form/footer/form_timeline.js:126 +#: public/js/frappe/form/footer/form_timeline.js:128 #: public/js/frappe/form/sidebar/form_sidebar.js:86 msgid "{0} Web page views" msgstr "crwdns104094:0{0}crwdne104094:0" @@ -29998,7 +30101,7 @@ msgstr "crwdns104506:0{0}crwdne104506:0" msgid "{0} added" msgstr "crwdns104096:0{0}crwdne104096:0" -#: public/js/frappe/form/controls/data.js:203 +#: public/js/frappe/form/controls/data.js:204 msgid "{0} already exists. Select another name" msgstr "crwdns104098:0{0}crwdne104098:0" @@ -30056,7 +30159,7 @@ msgstr "crwdns104122:0{0}crwdnd104122:0{1}crwdnd104122:0{2}crwdne104122:0" msgid "{0} assigned {1}: {2}" msgstr "crwdns104124:0{0}crwdnd104124:0{1}crwdnd104124:0{2}crwdne104124:0" -#: public/js/frappe/form/footer/form_timeline.js:414 +#: public/js/frappe/form/footer/form_timeline.js:416 msgctxt "Form timeline" msgid "{0} attached {1}" msgstr "crwdns104126:0{0}crwdnd104126:0{1}crwdne104126:0" @@ -30094,7 +30197,7 @@ msgstr "crwdns104138:0{0}crwdnd104138:0{1}crwdne104138:0" msgid "{0} changed the values for {1} {2}" msgstr "crwdns104140:0{0}crwdnd104140:0{1}crwdnd104140:0{2}crwdne104140:0" -#: public/js/frappe/form/footer/form_timeline.js:443 +#: public/js/frappe/form/footer/form_timeline.js:445 msgctxt "Form timeline" msgid "{0} changed {1} to {2}" msgstr "crwdns104142:0{0}crwdnd104142:0{1}crwdnd104142:0{2}crwdne104142:0" @@ -30111,7 +30214,7 @@ msgstr "crwdns127900:0{0}crwdne127900:0" msgid "{0} created successfully" msgstr "crwdns104146:0{0}crwdne104146:0" -#: public/js/frappe/form/footer/form_timeline.js:139 +#: public/js/frappe/form/footer/form_timeline.js:141 #: public/js/frappe/form/sidebar/form_sidebar.js:107 msgid "{0} created this" msgstr "crwdns104148:0{0}crwdne104148:0" @@ -30203,7 +30306,7 @@ msgstr "crwdns104188:0{0}crwdne104188:0" msgid "{0} has left the conversation in {1} {2}" msgstr "crwdns104190:0{0}crwdnd104190:0{1}crwdnd104190:0{2}crwdne104190:0" -#: __init__.py:2493 +#: __init__.py:2499 msgid "{0} has no versions tracked." msgstr "crwdns104192:0{0}crwdne104192:0" @@ -30269,7 +30372,7 @@ msgstr "crwdns104220:0{0}crwdnd104220:0{1}crwdne104220:0" msgid "{0} is like {1}" msgstr "crwdns104222:0{0}crwdnd104222:0{1}crwdne104222:0" -#: email/doctype/email_account/email_account.py:176 +#: email/doctype/email_account/email_account.py:186 msgid "{0} is mandatory" msgstr "crwdns104224:0{0}crwdne104224:0" @@ -30349,7 +30452,7 @@ msgstr "crwdns104258:0{0}crwdnd104258:0{1}crwdne104258:0" msgid "{0} is one of {1}" msgstr "crwdns104260:0{0}crwdnd104260:0{1}crwdne104260:0" -#: email/doctype/email_account/email_account.py:277 model/naming.py:217 +#: email/doctype/email_account/email_account.py:293 model/naming.py:217 #: printing/doctype/print_format/print_format.py:91 utils/csvutils.py:153 msgid "{0} is required" msgstr "crwdns104262:0{0}crwdne104262:0" @@ -30362,15 +30465,15 @@ msgstr "crwdns104264:0{0}crwdne104264:0" msgid "{0} is within {1}" msgstr "crwdns104266:0{0}crwdnd104266:0{1}crwdne104266:0" -#: public/js/frappe/list/list_view.js:1601 +#: public/js/frappe/list/list_view.js:1655 msgid "{0} items selected" msgstr "crwdns104268:0{0}crwdne104268:0" -#: core/doctype/user/user.py:1328 +#: core/doctype/user/user.py:1343 msgid "{0} just impersonated as you. They gave this reason: {1}" msgstr "crwdns111448:0{0}crwdnd111448:0{1}crwdne111448:0" -#: public/js/frappe/form/footer/form_timeline.js:150 +#: public/js/frappe/form/footer/form_timeline.js:152 #: public/js/frappe/form/sidebar/form_sidebar.js:96 msgid "{0} last edited this" msgstr "crwdns104270:0{0}crwdne104270:0" @@ -30432,11 +30535,11 @@ msgstr "crwdns104296:0{0}crwdne104296:0" msgid "{0} not found" msgstr "crwdns104298:0{0}crwdne104298:0" -#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:992 +#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:1029 msgid "{0} of {1}" msgstr "crwdns104300:0{0}crwdnd104300:0{1}crwdne104300:0" -#: public/js/frappe/list/list_view.js:994 +#: public/js/frappe/list/list_view.js:1031 msgid "{0} of {1} ({2} rows with children)" msgstr "crwdns104302:0{0}crwdnd104302:0{1}crwdnd104302:0{2}crwdne104302:0" @@ -30469,11 +30572,11 @@ msgstr "crwdns104312:0{0}crwdnd104312:0{1}crwdne104312:0" msgid "{0} records deleted" msgstr "crwdns104314:0{0}crwdne104314:0" -#: public/js/frappe/data_import/data_exporter.js:228 +#: public/js/frappe/data_import/data_exporter.js:229 msgid "{0} records will be exported" msgstr "crwdns104316:0{0}crwdne104316:0" -#: public/js/frappe/form/footer/form_timeline.js:419 +#: public/js/frappe/form/footer/form_timeline.js:421 msgctxt "Form timeline" msgid "{0} removed attachment {1}" msgstr "crwdns104318:0{0}crwdnd104318:0{1}crwdne104318:0" @@ -30565,7 +30668,7 @@ msgstr "crwdns104354:0{0}crwdne104354:0" msgid "{0} values selected" msgstr "crwdns104356:0{0}crwdne104356:0" -#: public/js/frappe/form/footer/form_timeline.js:183 +#: public/js/frappe/form/footer/form_timeline.js:185 msgid "{0} viewed this" msgstr "crwdns104358:0{0}crwdne104358:0" @@ -30609,7 +30712,7 @@ msgstr "crwdns104376:0{0}crwdnd104376:0{1}crwdne104376:0" msgid "{0} {1} does not exist, select a new target to merge" msgstr "crwdns104378:0{0}crwdnd104378:0{1}crwdne104378:0" -#: public/js/frappe/form/form.js:946 +#: public/js/frappe/form/form.js:950 msgid "{0} {1} is linked with the following submitted documents: {2}" msgstr "crwdns104380:0{0}crwdnd104380:0{1}crwdnd104380:0{2}crwdne104380:0" @@ -30617,7 +30720,7 @@ msgstr "crwdns104380:0{0}crwdnd104380:0{1}crwdnd104380:0{2}crwdne104380:0" msgid "{0} {1} not found" msgstr "crwdns104382:0{0}crwdnd104382:0{1}crwdne104382:0" -#: model/delete_doc.py:242 +#: model/delete_doc.py:251 msgid "{0} {1}: Submitted Record cannot be deleted. You must {2} Cancel {3} it first." msgstr "crwdns104384:0{0}crwdnd104384:0{1}crwdnd104384:0{2}crwdnd104384:0{3}crwdne104384:0" @@ -30709,7 +30812,7 @@ msgstr "crwdns111372:0{0}crwdne111372:0" msgid "{0}: Permission at level 0 must be set before higher levels are set" msgstr "crwdns104426:0{0}crwdne104426:0" -#: public/js/frappe/form/controls/data.js:50 +#: public/js/frappe/form/controls/data.js:51 msgid "{0}: You can increase the limit for the field if required via {1}" msgstr "crwdns104428:0{0}crwdnd104428:0{1}crwdne104428:0" @@ -30793,8 +30896,8 @@ msgstr "crwdns104456:0crwdne104456:0" msgid "{} field cannot be empty." msgstr "crwdns104458:0crwdne104458:0" -#: email/doctype/email_account/email_account.py:200 -#: email/doctype/email_account/email_account.py:208 +#: email/doctype/email_account/email_account.py:216 +#: email/doctype/email_account/email_account.py:224 msgid "{} has been disabled. It can only be enabled if {} is checked." msgstr "crwdns104460:0crwdne104460:0" diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po index f9bd261dfa..4e1e7877d5 100644 --- a/frappe/locale/sv.po +++ b/frappe/locale/sv.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-07-07 09:33+0000\n" -"PO-Revision-Date: 2024-07-14 17:15\n" +"POT-Creation-Date: 2024-07-21 09:33+0000\n" +"PO-Revision-Date: 2024-07-23 01:05\n" "Last-Translator: developers@frappe.io\n" "Language-Team: Swedish\n" "MIME-Version: 1.0\n" @@ -44,7 +44,7 @@ msgstr "'Överordnad' betyder överordnad tabell där denna rad skall infogas" msgid "\"Team Members\" or \"Management\"" msgstr "\"Team Medlemmar\" eller \"Ledning\"" -#: public/js/frappe/form/form.js:1085 +#: public/js/frappe/form/form.js:1089 msgid "\"amended_from\" field must be present to do an amendment." msgstr "'amend_from' fält måste finnas att skapa ändring." @@ -98,7 +98,7 @@ msgstr "'{0}' är inte en giltig webbadress" msgid "'{0}' not allowed for type {1} in row {2}" msgstr "'{0}' är otillåtet för typ {1} på rad {2}" -#: public/js/frappe/data_import/data_exporter.js:301 +#: public/js/frappe/data_import/data_exporter.js:302 msgid "(Mandatory)" msgstr "(Erfodrad)" @@ -168,7 +168,7 @@ msgstr "1 minut sedan" msgid "1 month ago" msgstr "1 månad sedan" -#: public/js/frappe/data_import/data_exporter.js:226 +#: public/js/frappe/data_import/data_exporter.js:227 msgid "1 record will be exported" msgstr "1 post exporteras" @@ -627,7 +627,7 @@ msgstr "

    För att interagera med ovanstående HTML måste du använda `root_el "some_class_element.textContent = \"Ny innehåll\";\n" "" -#: twofactor.py:462 +#: twofactor.py:446 msgid "

    Your OTP secret on {0} has been reset. If you did not perform this reset and did not request it, please contact your System Administrator immediately.

    " msgstr "

    Din OTP-hemlighet på {0} har återställts. Om du inte utförde denna återställning och inte begärde den, kontakta din systemadministratör omedelbart.

    " @@ -838,10 +838,11 @@ msgid "API Endpoint Args" msgstr "API Slutpunkt Argument" #. Label of the api_key (Data) field in DocType 'User' +#. Label of the api_key (Data) field in DocType 'Email Account' #. Label of the api_key (Data) field in DocType 'Google Settings' #. Label of the sb_01 (Section Break) field in DocType 'Google Settings' #. Label of the api_key (Data) field in DocType 'Push Notification Settings' -#: core/doctype/user/user.json +#: core/doctype/user/user.json email/doctype/email_account/email_account.json #: integrations/doctype/google_settings/google_settings.json #: integrations/doctype/push_notification_settings/push_notification_settings.json msgid "API Key" @@ -864,9 +865,10 @@ msgid "API Method" msgstr "API Metod" #. Label of the api_secret (Password) field in DocType 'User' +#. Label of the api_secret (Password) field in DocType 'Email Account' #. Label of the api_secret (Password) field in DocType 'Push Notification #. Settings' -#: core/doctype/user/user.json +#: core/doctype/user/user.json email/doctype/email_account/email_account.json #: integrations/doctype/push_notification_settings/push_notification_settings.json msgid "API Secret" msgstr "API Hemlighet " @@ -1102,7 +1104,7 @@ msgstr "Aktiva Sessioner" #. Group in User's connections #: core/doctype/user/user.json public/js/frappe/form/dashboard.js:22 -#: public/js/frappe/form/footer/form_timeline.js:58 +#: public/js/frappe/form/footer/form_timeline.js:60 msgid "Activity" msgstr "Aktivitet" @@ -1131,11 +1133,6 @@ msgstr "Aktivitet Logg" msgid "Add" msgstr "Lägga till" -#: public/js/frappe/list/list_view.js:266 -msgctxt "Primary action in list view" -msgid "Add" -msgstr "Lägg till" - #: public/js/frappe/form/grid_row.js:431 msgid "Add / Remove Columns" msgstr "Lägg till/Ta Bort Kolumn" @@ -1173,6 +1170,10 @@ msgstr "Lägg till Kant Längst Ner" msgid "Add Border at Top" msgstr "Lägg till Kant Längst Upp" +#: desk/doctype/number_card/number_card.js:36 +msgid "Add Card to Dashboard" +msgstr "Lägg till i Översikt Panel" + #: public/js/frappe/views/reports/query_report.js:210 msgid "Add Chart to Dashboard" msgstr "Lägg till Diagram i Översikt Panel" @@ -1247,7 +1248,7 @@ msgstr "Lägg till Fråge Parametrar" msgid "Add Review" msgstr "Lägg till Recension" -#: core/doctype/user/user.py:757 +#: core/doctype/user/user.py:772 msgid "Add Roles" msgstr "Lägg till Roller" @@ -1280,7 +1281,7 @@ msgstr "Lägg till Prenumeranter" msgid "Add Tags" msgstr "Lägg till Taggar" -#: public/js/frappe/list/list_view.js:1903 +#: public/js/frappe/list/list_view.js:1957 msgctxt "Button in list view actions menu" msgid "Add Tags" msgstr "Lägg till Taggar" @@ -1316,7 +1317,7 @@ msgstr "Lägg till Filter" msgid "Add a New Role" msgstr "Lägg till Ny Regel " -#: public/js/frappe/form/form_tour.js:205 +#: public/js/frappe/form/form_tour.js:211 msgid "Add a Row" msgstr "Lägg till Rad" @@ -1366,7 +1367,7 @@ msgstr "Lägg till i Att-Göra lista" msgid "Add to table" msgstr "Lägg till Tabell" -#: public/js/frappe/form/footer/form_timeline.js:97 +#: public/js/frappe/form/footer/form_timeline.js:99 msgid "Add to this activity by mailing to {0}" msgstr "Lägg till den här aktiviteten genom att skicka E-post till {0}" @@ -1374,6 +1375,11 @@ msgstr "Lägg till den här aktiviteten genom att skicka E-post till {0}" msgid "Add {0}" msgstr "Lägg till {0} " +#: public/js/frappe/list/list_view.js:264 +msgctxt "Primary action in list view" +msgid "Add {0}" +msgstr "Lägg till {0} " + #. Description of the '<head> HTML' (Code) field in DocType 'Website #. Settings' #: website/doctype/website_settings/website_settings.json @@ -1397,8 +1403,11 @@ msgstr "la till {0} ({1})" #. DocPerm' #. Label of the additional_permissions (Section Break) field in DocType #. 'DocPerm' +#. Label of the additional_permissions_section (Section Break) field in DocType +#. 'User Document Type' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json +#: core/doctype/user_document_type/user_document_type.json msgid "Additional Permissions" msgstr "Extra Behörigheter" @@ -1493,11 +1502,11 @@ msgstr "Administration" msgid "Administrator" msgstr "Administratör" -#: core/doctype/user/user.py:1161 +#: core/doctype/user/user.py:1176 msgid "Administrator Logged In" msgstr "Administratör Inloggad" -#: core/doctype/user/user.py:1155 +#: core/doctype/user/user.py:1170 msgid "Administrator accessed {0} on {1} via IP Address {2}." msgstr "Administratör loggade in {0} {1} via IP Adress {2}." @@ -1653,7 +1662,7 @@ msgstr "Alla Bilder bifogade till Hemsida Bildspel ska vara publika" msgid "All Records" msgstr "Alla Poster" -#: public/js/frappe/form/form.js:2225 +#: public/js/frappe/form/form.js:2230 msgid "All Submissions" msgstr "Alla Godkännande" @@ -1971,11 +1980,11 @@ msgstr "Tillåtna Moduler" msgid "Allowed Roles" msgstr "Tillåtna Roller" -#: public/js/frappe/form/form.js:1251 +#: public/js/frappe/form/form.js:1255 msgid "Allowing DocType, DocType. Be careful!" msgstr "Tillåter DocType, DocType. Var försiktig!" -#: core/doctype/user/user.py:964 +#: core/doctype/user/user.py:979 msgid "Already Registered" msgstr "Redan Registrerad" @@ -2187,11 +2196,11 @@ msgstr "App Namn" msgid "App Secret Key" msgstr "Hemliget" -#: modules/utils.py:275 +#: modules/utils.py:279 msgid "App not found for module: {0}" msgstr "App hittades inte för modul: {0}" -#: __init__.py:1794 +#: __init__.py:1800 msgid "App {0} is not installed" msgstr "App {0} är inte installerad" @@ -2211,7 +2220,7 @@ msgstr "Lägg E-post meddelande till Skickad Mapp" msgid "Append To" msgstr "E-post Till" -#: email/doctype/email_account/email_account.py:185 +#: email/doctype/email_account/email_account.py:195 msgid "Append To can be one of {0}" msgstr "E-post Till kan vara en av {0}" @@ -2252,7 +2261,7 @@ msgstr "Applikation Version" msgid "Applied On" msgstr "Tillämpad På" -#: public/js/frappe/list/list_view.js:1888 +#: public/js/frappe/list/list_view.js:1942 msgctxt "Button in list view actions menu" msgid "Apply Assignment Rule" msgstr "Tillämpa Tilldelning Regel" @@ -2346,7 +2355,7 @@ msgstr "Arkiverad" msgid "Archived Columns" msgstr "Arkiverade Kolumner" -#: public/js/frappe/list/list_view.js:1867 +#: public/js/frappe/list/list_view.js:1921 msgid "Are you sure you want to clear the assignments?" msgstr "Är du säker på att du vill ta bort tilldelningar?" @@ -2442,7 +2451,7 @@ msgstr "Tilldela Villkor" msgid "Assign To" msgstr "Tilldela till" -#: public/js/frappe/list/list_view.js:1849 +#: public/js/frappe/list/list_view.js:1903 msgctxt "Button in list view actions menu" msgid "Assign To" msgstr "Tilldela till" @@ -2561,7 +2570,7 @@ msgstr "Tilldelning Regel är ej tillåtet på {0} dokument typ" msgid "Assignment Rules" msgstr "Tilldelning Regler" -#: desk/doctype/notification_log/notification_log.py:157 +#: desk/doctype/notification_log/notification_log.py:158 msgid "Assignment Update on {0}" msgstr "Tilldelning Uppdatering {0}" @@ -2749,7 +2758,15 @@ msgstr "Autentisering" msgid "Authentication Apps you can use are: " msgstr "Autentisering App som kan användas är: " -#: email/doctype/email_account/email_account.py:312 +#: email/frappemail.py:89 +msgid "Authentication Error: Invalid API Key or Secret" +msgstr "Autentiseringsfel: Ogiltig API Nyckel eller Hemlighet" + +#: email/frappemail.py:85 +msgid "Authentication Error: Reauthorize OAuth for Email Account {0}." +msgstr "Autentiseringsfel: Återauktorisera OAuth för E-post Konto {0}." + +#: email/doctype/email_account/email_account.py:328 msgid "Authentication failed while receiving emails from Email Account: {0}." msgstr "Autentisering misslyckades när E-post meddelande togs emot från E-post Konto: {0}." @@ -2963,11 +2980,11 @@ msgstr "Automatiskt Meddelande" msgid "Automatic" msgstr "Automatisk" -#: email/doctype/email_account/email_account.py:715 +#: email/doctype/email_account/email_account.py:766 msgid "Automatic Linking can be activated only for one Email Account." msgstr "Automatisk länkning kan endast aktiveras för ett E-post konto." -#: email/doctype/email_account/email_account.py:709 +#: email/doctype/email_account/email_account.py:760 msgid "Automatic Linking can be activated only if Incoming is enabled." msgstr "Automatisk länkning kan endast aktiveras om Inkommande E-post är aktiverad." @@ -4006,7 +4023,7 @@ msgstr "Kan inte byta namn på {0} till {1} eftersom {0} inte finns." msgid "Cancel" msgstr "Annullera" -#: public/js/frappe/list/list_view.js:1958 +#: public/js/frappe/list/list_view.js:2012 msgctxt "Button in list view actions menu" msgid "Cancel" msgstr "Annullera" @@ -4016,11 +4033,11 @@ msgctxt "Secondary button in warning dialog" msgid "Cancel" msgstr "Annullera" -#: public/js/frappe/form/form.js:974 +#: public/js/frappe/form/form.js:978 msgid "Cancel All" msgstr "Annullera" -#: public/js/frappe/form/form.js:961 +#: public/js/frappe/form/form.js:965 msgid "Cancel All Documents" msgstr "Annullera Alla Dokument" @@ -4028,7 +4045,7 @@ msgstr "Annullera Alla Dokument" msgid "Cancel Scheduling" msgstr "Annullera Schemaläggning" -#: public/js/frappe/list/list_view.js:1963 +#: public/js/frappe/list/list_view.js:2017 msgctxt "Title of confirmation dialog" msgid "Cancel {0} documents?" msgstr "Annullera {0} dokument?" @@ -4128,7 +4145,7 @@ msgstr "Kan inte skapa privat arbetsyta för andra användare" msgid "Cannot delete Home and Attachments folders" msgstr "Kan inte radera Hem och Bilaga mappar" -#: model/delete_doc.py:373 +#: model/delete_doc.py:382 msgid "Cannot delete or cancel because {0} {1} is linked with {2} {3} {4}" msgstr "Kan inte ta bort eller annullera eftersom {0} {1} är länkat till {2} {3} {4}" @@ -4241,9 +4258,9 @@ msgstr "Kan inte ta bort ID fält" msgid "Cannot set 'Report' permission if 'Only If Creator' permission is set" msgstr "Kan inte ange \"Rapport\" behörighet om behörighet \"Endast om Ägare\" är angiven" -#: email/doctype/notification/notification.py:138 -msgid "Cannot set Notification on Document Type {0}" -msgstr "Kan inte ange Avisering för DocType {0}" +#: email/doctype/notification/notification.py:139 +msgid "Cannot set Notification with event {0} on Document Type {1}" +msgstr "Kan inte ange Avisering med händelse {0} på Dokument Typ {1}" #: core/doctype/docshare/docshare.py:67 msgid "Cannot share {0} with submit permission as the doctype {1} is not submittable" @@ -4590,7 +4607,7 @@ msgstr "Rensa & Lägg till Mall" msgid "Clear & Add template" msgstr "Rensa & Lägg till Mall" -#: public/js/frappe/list/list_view.js:1864 +#: public/js/frappe/list/list_view.js:1918 msgctxt "Button in list view actions menu" msgid "Clear Assignment" msgstr "Rensa Tilldelning" @@ -4689,7 +4706,7 @@ msgstr "Klicka på att Ange Dynamisk Filter" msgid "Click to Set Filters" msgstr "Klicka på att Ange Filter" -#: public/js/frappe/list/list_view.js:680 +#: public/js/frappe/list/list_view.js:679 msgid "Click to sort by {0}" msgstr "Klicka på att sortera efter {0}" @@ -4769,7 +4786,8 @@ msgid "Client URLs" msgstr "Klient Adresser" #: core/doctype/communication/communication.js:39 desk/doctype/todo/todo.js:23 -#: public/js/frappe/ui/messages.js:243 website/js/bootstrap-4.js:24 +#: public/js/frappe/form/form_tour.js:17 public/js/frappe/ui/messages.js:244 +#: website/js/bootstrap-4.js:24 msgid "Close" msgstr "Stäng" @@ -4824,7 +4842,7 @@ msgstr "Kod Redigerare Typ" msgid "Code challenge method" msgstr "Kod utmaning sätt" -#: public/js/frappe/form/form_tour.js:270 +#: public/js/frappe/form/form_tour.js:276 #: public/js/frappe/widgets/base_widget.js:159 msgid "Collapse" msgstr "Fäll In" @@ -5126,7 +5144,7 @@ msgstr "Klar" msgid "Complete By" msgstr "Klar Senast" -#: core/doctype/user/user.py:426 templates/emails/new_user.html:10 +#: core/doctype/user/user.py:432 templates/emails/new_user.html:10 msgid "Complete Registration" msgstr "Slutför Registrering" @@ -5690,7 +5708,7 @@ msgstr "Skapa Logg" msgid "Create New" msgstr "Skapa Ny" -#: public/js/frappe/list/list_view.js:487 +#: public/js/frappe/list/list_view.js:484 msgctxt "Create a new document from list view" msgid "Create New" msgstr "Skapa Ny " @@ -5730,7 +5748,7 @@ msgstr "Skapa ny Post" #: public/js/frappe/form/controls/link.js:295 #: public/js/frappe/form/controls/link.js:297 #: public/js/frappe/form/link_selector.js:139 -#: public/js/frappe/list/list_view.js:476 +#: public/js/frappe/list/list_view.js:473 #: public/js/frappe/web_form/web_form_list.js:225 msgid "Create a new {0}" msgstr "Skapa {0}" @@ -5757,7 +5775,7 @@ msgstr "Skapa eller Redigera Utskrift Format" msgid "Create or Edit Workflow" msgstr "Skapa eller Redigera Arbetsflöde" -#: public/js/frappe/list/list_view.js:479 +#: public/js/frappe/list/list_view.js:476 msgid "Create your first {0}" msgstr "Skapa {0}" @@ -5788,7 +5806,7 @@ msgid "Created Custom Field {0} in {1}" msgstr "Skapade Anpassad Fält {0} i {1}" #: desk/doctype/dashboard_chart/dashboard_chart.js:241 -#: email/doctype/notification/notification.js:30 model/meta.py:46 +#: email/doctype/notification/notification.js:33 model/meta.py:46 #: public/js/frappe/model/meta.js:198 public/js/frappe/model/model.js:125 #: public/js/frappe/views/dashboard/dashboard_view.js:478 msgid "Created On" @@ -6147,7 +6165,7 @@ msgstr "Anpassningar Bortkastade" msgid "Customizations Reset" msgstr "Anpassningar Återställda " -#: modules/utils.py:91 +#: modules/utils.py:95 msgid "Customizations for {0} exported to:
    {1}" msgstr "Anpassningar för {0} som exporterades till:
    {1}" @@ -6158,7 +6176,7 @@ msgstr "Anpassningar för {0} som exporterades till:
    {1}" msgid "Customize" msgstr "Anpassa" -#: public/js/frappe/list/list_view.js:1709 +#: public/js/frappe/list/list_view.js:1763 msgctxt "Button in list view menu" msgid "Customize" msgstr "Anpassa" @@ -6173,6 +6191,7 @@ msgstr "Anpassa Översikt Panel" #. Name of a DocType #: automation/doctype/auto_repeat/auto_repeat.js:33 +#: core/doctype/doctype/doctype.js:65 #: custom/doctype/customize_form/customize_form.json #: public/js/frappe/views/kanban/kanban_view.js:343 msgid "Customize Form" @@ -6403,7 +6422,7 @@ msgstr "Översikt Paneler" msgid "Data" msgstr "Data" -#: public/js/frappe/form/controls/data.js:58 +#: public/js/frappe/form/controls/data.js:59 msgid "Data Clipped" msgstr "Data Urklippt" @@ -6508,6 +6527,7 @@ msgstr "Datum Format" #. Trail' #: core/doctype/audit_trail/audit_trail.json #: desk/page/leaderboard/leaderboard.js:165 +#: public/js/frappe/widgets/chart_widget.js:237 msgid "Date Range" msgstr "Datum Intervall" @@ -6641,7 +6661,7 @@ msgstr "Standard Inkorg" #. Label of the default_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:201 +#: email/doctype/email_account/email_account.py:217 msgid "Default Incoming" msgstr "Standard Inkommande" @@ -6661,7 +6681,7 @@ msgstr "Standard Nummer Serie" #. Label of the default_outgoing (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:209 +#: email/doctype/email_account/email_account.py:225 msgid "Default Outgoing" msgstr "Standard Utgående" @@ -6776,7 +6796,7 @@ msgstr "Standard Värde" msgid "Defaults" msgstr "Standard" -#: email/doctype/email_account/email_account.py:220 +#: email/doctype/email_account/email_account.py:236 msgid "Defaults Updated" msgstr "Standard Inställningar Uppdaterade" @@ -6802,7 +6822,7 @@ msgstr "Försenad" #: core/doctype/docperm/docperm.json #: core/doctype/user_document_type/user_document_type.json #: core/doctype/user_permission/user_permission_list.js:189 -#: public/js/frappe/form/footer/form_timeline.js:613 +#: public/js/frappe/form/footer/form_timeline.js:615 #: public/js/frappe/form/grid.js:63 public/js/frappe/form/toolbar.js:434 #: public/js/frappe/views/reports/report_view.js:1654 #: public/js/frappe/views/treeview.js:308 @@ -6812,7 +6832,7 @@ msgstr "Försenad" msgid "Delete" msgstr "Ta Bort" -#: public/js/frappe/list/list_view.js:1926 +#: public/js/frappe/list/list_view.js:1980 msgctxt "Button in list view actions menu" msgid "Delete" msgstr "Ta Bort" @@ -6841,7 +6861,7 @@ msgstr "Ta Bort Arbetsyta" msgid "Delete and Generate New" msgstr "Ta bort och Skapa Ny" -#: public/js/frappe/form/footer/form_timeline.js:719 +#: public/js/frappe/form/footer/form_timeline.js:721 msgid "Delete comment?" msgstr "Ta Bort Kommentar?" @@ -6849,12 +6869,12 @@ msgstr "Ta Bort Kommentar?" msgid "Delete this record to allow sending to this email address" msgstr "Ta Bort denna post för att tillåta utskick till denna E-post" -#: public/js/frappe/list/list_view.js:1931 +#: public/js/frappe/list/list_view.js:1985 msgctxt "Title of confirmation dialog" msgid "Delete {0} item permanently?" msgstr "Ta Bort {0} Post permanent?" -#: public/js/frappe/list/list_view.js:1937 +#: public/js/frappe/list/list_view.js:1991 msgctxt "Title of confirmation dialog" msgid "Delete {0} items permanently?" msgstr "Radera {0} Poster permanent?" @@ -7093,7 +7113,7 @@ msgstr "Skrivbord Ikon finns redan" #: desk/doctype/event/event.json #: desk/page/user_profile/user_profile_sidebar.html:45 #: public/js/form_builder/store.js:259 public/js/form_builder/utils.js:38 -#: public/js/frappe/form/layout.js:135 public/js/frappe/views/treeview.js:271 +#: public/js/frappe/form/layout.js:137 public/js/frappe/views/treeview.js:271 msgid "Details" msgstr "Detaljer" @@ -7241,7 +7261,7 @@ msgstr "Inaktivera Registrering" msgid "Disabled" msgstr "Inaktiverad" -#: email/doctype/email_account/email_account.js:232 +#: email/doctype/email_account/email_account.js:261 msgid "Disabled Auto Reply" msgstr "Inaktiverad Autosvar" @@ -7258,7 +7278,7 @@ msgctxt "Button in web form" msgid "Discard" msgstr "Avvisa" -#: public/js/frappe/form/form.js:840 +#: public/js/frappe/form/form.js:844 msgid "Discard {0}" msgstr "Avvisa {0}" @@ -7285,7 +7305,7 @@ msgstr "Diskussion Svar" msgid "Discussion Topic" msgstr "Diskussion Ämne" -#: public/js/frappe/form/footer/form_timeline.js:623 +#: public/js/frappe/form/footer/form_timeline.js:625 #: templates/discussions/reply_card.html:16 #: templates/discussions/reply_section.html:29 msgid "Dismiss" @@ -7336,7 +7356,7 @@ msgstr "Behörigheter saknas att komma åt skop {0}." msgid "Do you still want to proceed?" msgstr "Vill du fortfarande fortsätta?" -#: public/js/frappe/form/form.js:953 +#: public/js/frappe/form/form.js:957 msgid "Do you want to cancel all linked documents?" msgstr "Vill du annullera alla länkade dokument?" @@ -7514,11 +7534,11 @@ msgstr "DocType Arbetsflöde kan tillämpas på." msgid "DocType required" msgstr "DocType erfodras" -#: modules/utils.py:170 +#: modules/utils.py:174 msgid "DocType {0} does not exist." msgstr "DocType {0} finns inte." -#: modules/utils.py:233 +#: modules/utils.py:237 msgid "DocType {} not found" msgstr "DocType {} hittades inte" @@ -7624,7 +7644,7 @@ msgstr "Dokument Länkar Rad #{0}: Tabell Fält namn erfodras för interna länk #: core/doctype/user_permission/user_permission_list.js:36 #: core/doctype/version/version.json desk/doctype/tag_link/tag_link.json #: email/doctype/document_follow/document_follow.json -#: public/js/frappe/form/form_tour.js:60 +#: public/js/frappe/form/form_tour.js:62 msgid "Document Name" msgstr "Dokument Namn" @@ -7808,15 +7828,15 @@ msgstr "Dokument Typer och Behörigheter" msgid "Document Unlocked" msgstr "Dokument Upplåst" -#: public/js/frappe/list/list_view.js:1081 +#: public/js/frappe/list/list_view.js:1118 msgid "Document has been cancelled" msgstr "Dokumentet är annullerad" -#: public/js/frappe/list/list_view.js:1080 +#: public/js/frappe/list/list_view.js:1117 msgid "Document has been submitted" msgstr "Dokument är godkänd" -#: public/js/frappe/list/list_view.js:1079 +#: public/js/frappe/list/list_view.js:1116 msgid "Document is in draft state" msgstr "Dokumentet är i utkast tillstånd" @@ -7939,7 +7959,7 @@ msgstr "Koda inte HTML-taggar som <script> eller bara tecken som < elle msgid "Don't have an account?" msgstr "Har du inget konto?" -#: public/js/frappe/ui/messages.js:231 +#: public/js/frappe/form/form_tour.js:16 public/js/frappe/ui/messages.js:231 #: public/js/onboarding_tours/onboarding_tours.js:17 msgid "Done" msgstr "Klart" @@ -8178,8 +8198,8 @@ msgstr "Varje dokument skapad i System kan ha unikt ID genererad för det, med d #: printing/page/print_format_builder_beta/print_format_builder_beta.js:46 #: printing/page/print_format_builder_beta/print_format_builder_beta.js:85 #: public/js/frappe/form/controls/markdown_editor.js:31 -#: public/js/frappe/form/footer/form_timeline.js:652 -#: public/js/frappe/form/footer/form_timeline.js:661 +#: public/js/frappe/form/footer/form_timeline.js:654 +#: public/js/frappe/form/footer/form_timeline.js:663 #: public/js/frappe/form/templates/address_list.html:7 #: public/js/frappe/form/templates/contact_list.html:7 #: public/js/frappe/form/toolbar.js:681 @@ -8188,7 +8208,7 @@ msgstr "Varje dokument skapad i System kan ha unikt ID genererad för det, med d #: public/js/frappe/views/workspace/workspace.js:460 #: public/js/frappe/views/workspace/workspace.js:816 #: public/js/frappe/widgets/base_widget.js:64 -#: public/js/frappe/widgets/chart_widget.js:298 +#: public/js/frappe/widgets/chart_widget.js:299 #: public/js/frappe/widgets/number_card_widget.js:331 #: templates/discussions/reply_card.html:29 #: templates/discussions/reply_section.html:29 @@ -8197,7 +8217,7 @@ msgstr "Varje dokument skapad i System kan ha unikt ID genererad för det, med d msgid "Edit" msgstr "Redigera" -#: public/js/frappe/list/list_view.js:2012 +#: public/js/frappe/list/list_view.js:2066 msgctxt "Button in list view actions menu" msgid "Edit" msgstr "Redigera" @@ -8227,7 +8247,7 @@ msgstr "Redigera Anpassad HTML" msgid "Edit DocType" msgstr "Redigera DocType" -#: public/js/frappe/list/list_view.js:1736 +#: public/js/frappe/list/list_view.js:1790 msgctxt "Button in list view menu" msgid "Edit DocType" msgstr "Redigera DocType" @@ -8373,6 +8393,7 @@ msgstr "Element Väljare" #. Label of the email_tab (Tab Break) field in DocType 'System Settings' #. Label of the email (Data) field in DocType 'User' #. Label of the email_settings (Section Break) field in DocType 'User' +#. Label of the email (Check) field in DocType 'User Document Type' #. Label of the email (Data) field in DocType 'Event Participants' #. Label of the email (Data) field in DocType 'Email Group Member' #. Label of the email (Data) field in DocType 'Email Unsubscribe' @@ -8385,6 +8406,7 @@ msgstr "Element Väljare" #: core/doctype/success_action/success_action.js:57 #: core/doctype/system_settings/system_settings.json #: core/doctype/user/user.json +#: core/doctype/user_document_type/user_document_type.json #: desk/doctype/event_participants/event_participants.json #: email/doctype/email_group_member/email_group_member.json #: email/doctype/email_unsubscribe/email_unsubscribe.json @@ -8420,7 +8442,7 @@ msgctxt "Email Account" msgid "Email Account" msgstr "E-post Konto" -#: email/doctype/email_account/email_account.py:316 +#: email/doctype/email_account/email_account.py:332 msgid "Email Account Disabled." msgstr "E-post Konto Inaktiverad" @@ -8429,7 +8451,7 @@ msgstr "E-post Konto Inaktiverad" msgid "Email Account Name" msgstr "E-post Konto Namn" -#: core/doctype/user/user.py:690 +#: core/doctype/user/user.py:705 msgid "Email Account added multiple times" msgstr "E-post Konto lagt till flera gånger" @@ -8725,7 +8747,7 @@ msgstr "Aktivera Google Indexering" #. Label of the enable_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:202 +#: email/doctype/email_account/email_account.py:218 msgid "Enable Incoming" msgstr "Aktivera Inkommande" @@ -8738,7 +8760,7 @@ msgstr "Aktivera Introduktion" #. Label of the enable_outgoing (Check) field in DocType 'Email Account' #: core/doctype/user_email/user_email.json #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:210 +#: email/doctype/email_account/email_account.py:226 msgid "Enable Outgoing" msgstr "Aktivera Utgående" @@ -8809,7 +8831,7 @@ msgstr "Aktivera Spårning Sid Visningar" #. Label of the enable_two_factor_auth (Check) field in DocType 'System #. Settings' -#: core/doctype/system_settings/system_settings.json twofactor.py:449 +#: core/doctype/system_settings/system_settings.json twofactor.py:433 msgid "Enable Two Factor Auth" msgstr "Aktivera Två Faktor Autentisering" @@ -8879,7 +8901,7 @@ msgstr "Aktiverad" msgid "Enabled Scheduler" msgstr "Aktiverad Schemaläggare" -#: email/doctype/email_account/email_account.py:936 +#: email/doctype/email_account/email_account.py:987 msgid "Enabled email inbox for user {0}" msgstr "E-post Konto Aktiverad för {0}" @@ -8892,7 +8914,7 @@ msgstr "E-post Konto Aktiverad för {0}" msgid "Enables Calendar and Gantt views." msgstr "Aktiverar Kalender och Gantt Vyer." -#: email/doctype/email_account/email_account.js:227 +#: email/doctype/email_account/email_account.js:256 msgid "Enabling auto reply on an incoming email account will send automated replies to all the synchronized emails. Do you wish to continue?" msgstr "Om automatiskt svar aktiveras på inkommande E-post Konto, skickas automatiska svar på alla synkroniserade E-post meddelanden. Vill du fortsätta?" @@ -8990,7 +9012,7 @@ msgstr "Prestation Resultat Regel" msgid "Energy Point Settings" msgstr "Prestation Resultat Inställningar" -#: desk/doctype/notification_log/notification_log.py:159 +#: desk/doctype/notification_log/notification_log.py:160 msgid "Energy Point Update on {0}" msgstr "Prestation Resultat Uppdateras {0}" @@ -9000,6 +9022,8 @@ msgstr "Prestation Resultat Uppdateras {0}" #. 'Notification Settings' #: desk/doctype/notification_settings/notification_settings.json #: desk/page/user_profile/user_profile.html:28 +#: desk/page/user_profile/user_profile_controller.js:80 +#: desk/page/user_profile/user_profile_controller.js:114 #: desk/page/user_profile/user_profile_controller.js:402 #: templates/emails/energy_points_summary.html:39 msgid "Energy Points" @@ -9040,7 +9064,7 @@ msgctxt "Title of prompt dialog" msgid "Enter Value" msgstr "Ange Värde" -#: public/js/frappe/form/form_tour.js:58 +#: public/js/frappe/form/form_tour.js:60 msgid "Enter a name for this {0}" msgstr "Ange ett namn för denna {0}" @@ -9071,7 +9095,7 @@ msgstr "Ange url parameter för meddelande" msgid "Enter url parameter for receiver nos" msgstr "Ange url parameter för mottagare" -#: public/js/frappe/ui/messages.js:332 +#: public/js/frappe/ui/messages.js:334 msgid "Enter your password" msgstr "Ange Lösenord" @@ -9162,9 +9186,9 @@ msgstr "Fel i Klient Skript." msgid "Error in Header/Footer Script" msgstr "Fel i Sidhuvud/Sidfot Skript" -#: email/doctype/notification/notification.py:395 -#: email/doctype/notification/notification.py:511 -#: email/doctype/notification/notification.py:517 +#: email/doctype/notification/notification.py:443 +#: email/doctype/notification/notification.py:559 +#: email/doctype/notification/notification.py:565 msgid "Error in Notification" msgstr "Fel i Avisering" @@ -9172,11 +9196,11 @@ msgstr "Fel i Avisering" msgid "Error in print format on line {0}: {1}" msgstr "Fel i Utskrift Format på rad {0}: {1}" -#: email/doctype/email_account/email_account.py:614 +#: email/doctype/email_account/email_account.py:664 msgid "Error while connecting to email account {0}" msgstr "Fel vid anslutning till E-post Konto {0}" -#: email/doctype/notification/notification.py:508 +#: email/doctype/notification/notification.py:556 msgid "Error while evaluating Notification {0}. Please fix your template." msgstr "Fel vid test av Avisering {0}. Fixa Mall." @@ -9406,19 +9430,19 @@ msgstr "Förfallo Tid för QR Kod Bild Sida" #. Label of the export (Check) field in DocType 'DocPerm' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json core/doctype/recorder/recorder_list.js:37 -#: public/js/frappe/data_import/data_exporter.js:91 -#: public/js/frappe/data_import/data_exporter.js:242 +#: public/js/frappe/data_import/data_exporter.js:92 +#: public/js/frappe/data_import/data_exporter.js:243 #: public/js/frappe/views/reports/query_report.js:1669 #: public/js/frappe/views/reports/report_view.js:1550 msgid "Export" msgstr "Export" -#: public/js/frappe/list/list_view.js:2034 +#: public/js/frappe/list/list_view.js:2088 msgctxt "Button in list view actions menu" msgid "Export" msgstr "Export" -#: public/js/frappe/data_import/data_exporter.js:244 +#: public/js/frappe/data_import/data_exporter.js:245 msgid "Export 1 record" msgstr "Exportera 1 Post" @@ -9491,7 +9515,7 @@ msgstr "Exportera data utan några rubriker och kolumn beskrivning" msgid "Export without main header" msgstr "Exportera utan huvud rubrik" -#: public/js/frappe/data_import/data_exporter.js:246 +#: public/js/frappe/data_import/data_exporter.js:247 msgid "Export {0} records" msgstr "Exportera {0} poster" @@ -9644,7 +9668,7 @@ msgstr "Misslyckadesc att importera virtuell doctype {}, finns kontroll fil?" msgid "Failed to optimize image: {0}" msgstr "Misslyckades att optimera bild: {0}" -#: email/doctype/email_queue/email_queue.py:281 +#: email/doctype/email_queue/email_queue.py:294 msgid "Failed to send email with subject:" msgstr "Misslyckades att skicka e-post med ämne:" @@ -9824,10 +9848,14 @@ msgstr "Fält {0} finns inte på {1}" msgid "Field {0} is referring to non-existing doctype {1}." msgstr "Fält {0} hänvisar till icke-existerande doctype {1}." -#: public/js/frappe/form/form.js:1761 +#: public/js/frappe/form/form.js:1765 msgid "Field {0} not found." msgstr "Fält {0} hittades inte." +#: email/doctype/notification/notification.py:348 +msgid "Field {0} on document {1} is neither a Mobile number field nor a Customer or User link" +msgstr "Fält {0} på dokument {1} är varken mobil nummer fält, Kund eller Användarlänk" + #. Label of the fieldname (Data) field in DocType 'Report Column' #. Label of the fieldname (Data) field in DocType 'Report Filter' #. Label of the fieldname (Data) field in DocType 'Custom Field' @@ -9960,7 +9988,7 @@ msgctxt "File" msgid "File" msgstr "Fil" -#: core/doctype/file/utils.py:127 +#: core/doctype/file/utils.py:128 msgid "File '{0}' not found" msgstr "Fil '{0}' hittades inte" @@ -10502,6 +10530,10 @@ msgstr "För jämförelse, använd >5, <10 eller = 324. För intervall, använd msgid "For example if you cancel and amend INV004 it will become a new document INV004-1. This helps you to keep track of each amendment." msgstr "Om du till exempel annullerar och ändrar INV004 skapas ny dokument INV004-1. Detta hjälper med att hålla reda på varje ändring." +#: public/js/frappe/utils/dashboard_utils.js:162 +msgid "For example:" +msgstr "Till exempel:" + #: printing/page/print_format_builder/print_format_builder.js:744 msgid "For example: If you want to include the document ID, use {0}" msgstr "Till exempel: Om du vill inkludera Dokument ID, använd {0}" @@ -10681,6 +10713,20 @@ msgstr "Frappe Framework" msgid "Frappe Light" msgstr "Frappe Light" +#. Option for the 'Service' (Select) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json email/frappemail.py:91 +msgid "Frappe Mail" +msgstr "Frappe Mail" + +#: email/doctype/email_account/email_account.py:538 +msgid "Frappe Mail OAuth Error" +msgstr "Frappe Mail OAuth fel" + +#. Label of the frappe_mail_site (Data) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json +msgid "Frappe Mail Site" +msgstr "Frappe Mail Site" + #. Label of a standard help item #. Type: Action #: hooks.py @@ -10798,7 +10844,7 @@ msgstr "Funktion" msgid "Function Based On" msgstr "Funktion Baserad på" -#: __init__.py:934 +#: __init__.py:940 msgid "Function {0} is not whitelisted." msgstr "Funktion {0} är inte vitlistad." @@ -10885,7 +10931,7 @@ msgstr "Skapa Spårning URL" msgid "Geolocation" msgstr "Geolocation" -#: email/doctype/notification/notification.js:170 +#: email/doctype/notification/notification.js:193 msgid "Get Alerts for Today" msgstr "Hämta Dagens Alerts" @@ -11710,7 +11756,7 @@ msgstr "Dölj Sidofält, Meny och Kommentarer" msgid "Hide Standard Menu" msgstr "Dölj Standard Meny" -#: public/js/frappe/list/list_view.js:1611 +#: public/js/frappe/list/list_view.js:1665 msgid "Hide Tags" msgstr "Dölj Taggar" @@ -11728,7 +11774,7 @@ msgstr "Dölj Arbetsyta" msgid "Hide descendant records of For Value." msgstr "Dölj Underordnade poster för För Värde." -#: public/js/frappe/form/layout.js:268 +#: public/js/frappe/form/layout.js:270 msgid "Hide details" msgstr "Dölj Detaljer" @@ -11831,11 +11877,11 @@ msgstr "Hur ska denna valuta formateras? Om inte angiven, kommer system standard #: core/doctype/data_import/importer.py:1139 #: core/doctype/data_import/importer.py:1204 #: core/doctype/data_import/importer.py:1207 desk/report/todo/todo.py:36 -#: model/meta.py:45 public/js/frappe/data_import/data_exporter.js:329 -#: public/js/frappe/data_import/data_exporter.js:344 +#: model/meta.py:45 public/js/frappe/data_import/data_exporter.js:330 +#: public/js/frappe/data_import/data_exporter.js:345 #: public/js/frappe/list/list_settings.js:334 -#: public/js/frappe/list/list_view.js:358 -#: public/js/frappe/list/list_view.js:422 public/js/frappe/model/meta.js:197 +#: public/js/frappe/list/list_view.js:355 +#: public/js/frappe/list/list_view.js:419 public/js/frappe/model/meta.js:197 #: public/js/frappe/model/model.js:122 msgid "ID" msgstr "ID" @@ -12229,7 +12275,7 @@ msgstr "Bild Fält måste vara giltig Fält Namn" msgid "Image field must be of type Attach Image" msgstr "Bild Fält måste vara av typ Bifoga Bild" -#: core/doctype/file/utils.py:135 +#: core/doctype/file/utils.py:136 msgid "Image link '{0}' is not valid" msgstr "Bild Länk \"{0}\" är inte giltig" @@ -12237,6 +12283,10 @@ msgstr "Bild Länk \"{0}\" är inte giltig" msgid "Image optimized" msgstr "Bild Optimerad" +#: core/doctype/file/utils.py:283 +msgid "Image: Corrupted Data Stream" +msgstr "Bild: Skadad Dataström" + #: public/js/frappe/views/image/image_view.js:13 msgid "Images" msgstr "Bilder" @@ -12275,7 +12325,7 @@ msgstr "Implicit" msgid "Import" msgstr "Importera" -#: public/js/frappe/list/list_view.js:1673 +#: public/js/frappe/list/list_view.js:1727 msgctxt "Button in list view menu" msgid "Import" msgstr "Importera" @@ -12524,8 +12574,8 @@ msgstr "Inkludera symboler, siffror och stora bokstäver i lösenord" #. Label of the incoming_popimap_tab (Tab Break) field in DocType 'Email #. Account' #: email/doctype/email_account/email_account.json -msgid "Incoming (POP/IMAP)" -msgstr "Inkommande (POP/IMAP)" +msgid "Incoming" +msgstr "Inkommande" #. Label of the mailbox_settings (Section Break) field in DocType 'Email #. Account' @@ -12864,7 +12914,7 @@ msgid "Invalid" msgstr "Ogiltig" #: public/js/form_builder/utils.js:221 public/js/frappe/form/grid_row.js:770 -#: public/js/frappe/form/layout.js:793 +#: public/js/frappe/form/layout.js:795 msgid "Invalid \"depends_on\" expression" msgstr "Ogiltig 'depends_on' uttryck" @@ -12968,7 +13018,7 @@ msgstr "Ogiltig Åsidosättning" msgid "Invalid Parameters." msgstr "Ogiltiga Parametrar" -#: core/doctype/user/user.py:1176 www/update-password.html:121 +#: core/doctype/user/user.py:1191 www/update-password.html:121 #: www/update-password.html:142 www/update-password.html:144 #: www/update-password.html:245 msgid "Invalid Password" @@ -13337,7 +13387,7 @@ msgstr "Är Unik" msgid "Is Virtual" msgstr "Är Virtuell" -#: core/doctype/file/utils.py:156 utils/file_manager.py:311 +#: core/doctype/file/utils.py:157 utils/file_manager.py:311 msgid "It is risky to delete this file: {0}. Please contact your System Manager." msgstr "Det är riskabelt att radera denna fil: {0}. Kontakta System Administratör." @@ -13844,7 +13894,7 @@ msgstr "Senaste Kända Versioner" msgid "Last Login" msgstr "Senaste Inloggning" -#: email/doctype/notification/notification.js:31 +#: email/doctype/notification/notification.js:34 msgid "Last Modified Date" msgstr "Senast Ändrad Datum" @@ -13892,6 +13942,11 @@ msgstr "Senast Återställning Lösenord Nyckel Skapades" msgid "Last Sync On" msgstr "Senast Synkroniserad" +#. Label of the last_synced_at (Datetime) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json +msgid "Last Synced At" +msgstr "Senast Synkroniserad" + #. Label of the last_synced_on (Datetime) field in DocType 'Dashboard Chart' #: desk/doctype/dashboard_chart/dashboard_chart.json msgid "Last Synced On" @@ -13922,7 +13977,7 @@ msgstr "Förra Vecka" msgid "Last Year" msgstr "Förra Året" -#: public/js/frappe/widgets/chart_widget.js:698 +#: public/js/frappe/widgets/chart_widget.js:701 msgid "Last synced {0}" msgstr "Senast Synkroniserad {0}" @@ -13974,7 +14029,7 @@ msgid "Leave blank to repeat always" msgstr "Lämna tom för ingen slut datum" #: core/doctype/communication/mixins.py:207 -#: email/doctype/email_account/email_account.py:663 +#: email/doctype/email_account/email_account.py:714 msgid "Leave this conversation" msgstr "Lämna denna konversation" @@ -14033,7 +14088,7 @@ msgstr "Längd av datamatrisen är större än värdet för maximum tillåtna et msgid "Length of {0} should be between 1 and 1000" msgstr "Längd av {0} ska vara mellan 1 och 1000" -#: public/js/frappe/widgets/chart_widget.js:674 +#: public/js/frappe/widgets/chart_widget.js:677 msgid "Less" msgstr "Mindre" @@ -14116,6 +14171,7 @@ msgstr "Sidhuvud i HTML" #. Label of the level (Select) field in DocType 'Help Article' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json +#: core/page/permission_manager/permission_manager.js:137 #: core/page/permission_manager/permission_manager.js:213 #: public/js/frappe/roles_editor.js:66 #: website/doctype/help_article/help_article.json @@ -14418,7 +14474,7 @@ msgstr "List Inställning Meddelande" msgid "List Settings" msgstr "Lista Inställningar" -#: public/js/frappe/list/list_view.js:1753 +#: public/js/frappe/list/list_view.js:1807 msgctxt "Button in list view menu" msgid "List Settings" msgstr "Lista Inställningar" @@ -14469,7 +14525,7 @@ msgstr "Last Balansering" msgid "Load More" msgstr "Ladda Mer" -#: public/js/frappe/form/footer/form_timeline.js:214 +#: public/js/frappe/form/footer/form_timeline.js:216 msgctxt "Form timeline" msgid "Load More Communications" msgstr "Ladda Mer Korenspondens" @@ -14478,7 +14534,7 @@ msgstr "Ladda Mer Korenspondens" #: public/js/frappe/form/controls/multicheck.js:13 #: public/js/frappe/form/linked_with.js:13 #: public/js/frappe/list/base_list.js:498 -#: public/js/frappe/list/list_view.js:335 public/js/frappe/ui/listing.html:16 +#: public/js/frappe/list/list_view.js:332 public/js/frappe/ui/listing.html:16 #: public/js/frappe/views/reports/query_report.js:1017 msgid "Loading" msgstr "Laddar" @@ -14589,7 +14645,7 @@ msgstr "Logga in Före" msgid "Login Failed please try again" msgstr "Inloggning Misslyckades, försök igen" -#: email/doctype/email_account/email_account.py:141 +#: email/doctype/email_account/email_account.py:140 msgid "Login Id is required" msgstr "Inloggning Erfodras" @@ -15159,7 +15215,7 @@ msgstr "Sammanslafning är endast möjlig mellan grupp till grupp eller underord msgid "Message" msgstr "Meddelande" -#: __init__.py:618 public/js/frappe/ui/messages.js:265 +#: __init__.py:624 public/js/frappe/ui/messages.js:267 msgctxt "Default title of the message dialog" msgid "Message" msgstr "Meddelande" @@ -15200,7 +15256,7 @@ msgstr "Meddelande Typ" msgid "Message clipped" msgstr "Meddelande Urlippt" -#: email/doctype/email_account/email_account.py:317 +#: email/doctype/email_account/email_account.py:333 msgid "Message from server: {0}" msgstr "Meddelande från Server: {0}" @@ -15279,7 +15335,7 @@ msgstr "Meta Titel för SEO" msgid "Method" msgstr "Sätt" -#: __init__.py:936 +#: __init__.py:942 msgid "Method Not Allowed" msgstr "Metod ej Tillåten" @@ -15508,7 +15564,7 @@ msgstr "Modul Introduktion förlopp återställning" msgid "Module to Export" msgstr "Modul att Exportera" -#: modules/utils.py:268 +#: modules/utils.py:272 msgid "Module {} not found" msgstr "Modul {} hittades inte" @@ -15592,7 +15648,7 @@ msgstr "Månads Position" #: public/js/frappe/form/multi_select_dialog.js:72 #: public/js/frappe/ui/toolbar/search.js:285 #: public/js/frappe/ui/toolbar/search.js:300 -#: public/js/frappe/widgets/chart_widget.js:674 +#: public/js/frappe/widgets/chart_widget.js:677 #: templates/includes/list/list.html:23 #: templates/includes/search_template.html:13 msgid "More" @@ -15880,12 +15936,12 @@ msgstr "Toppfält Mall Värden" msgid "Navigate Home" msgstr "Navigera Hem" -#: public/js/frappe/list/list_view.js:1161 +#: public/js/frappe/list/list_view.js:1198 msgctxt "Description of a list view shortcut" msgid "Navigate list down" msgstr "Navigera lista ner" -#: public/js/frappe/list/list_view.js:1168 +#: public/js/frappe/list/list_view.js:1205 msgctxt "Description of a list view shortcut" msgid "Navigate list up" msgstr "Navigera lista upp" @@ -15969,11 +16025,11 @@ msgstr "Ny Anpassad Utskrift Mall" msgid "New Document Form" msgstr "Ny Dokument Form" -#: desk/doctype/notification_log/notification_log.py:158 +#: desk/doctype/notification_log/notification_log.py:159 msgid "New Document Shared {0}" msgstr "Ny Dokument Delad {0}" -#: public/js/frappe/form/footer/form_timeline.js:26 +#: public/js/frappe/form/footer/form_timeline.js:27 #: public/js/frappe/views/communication.js:23 msgid "New Email" msgstr "Ny E-post" @@ -15983,7 +16039,7 @@ msgstr "Ny E-post" msgid "New Email Account" msgstr "Ny E-post Konto" -#: public/js/frappe/form/footer/form_timeline.js:45 +#: public/js/frappe/form/footer/form_timeline.js:47 msgid "New Event" msgstr "Ny Händelse" @@ -15999,7 +16055,7 @@ msgstr "Ny Anslag Tavla" msgid "New Links" msgstr "Nya Länkar" -#: desk/doctype/notification_log/notification_log.py:156 +#: desk/doctype/notification_log/notification_log.py:157 msgid "New Mention on {0}" msgstr "Ny Hänvisning {0}" @@ -16017,7 +16073,7 @@ msgstr "Ny Namn" msgid "New Newsletter" msgstr "Ny Nyhetsbrev" -#: desk/doctype/notification_log/notification_log.py:155 +#: desk/doctype/notification_log/notification_log.py:156 msgid "New Notification" msgstr "Ny Avisering" @@ -16122,7 +16178,7 @@ msgstr "Ny {0}: {1}" msgid "New {} releases for the following apps are available" msgstr "Nya {} versioner för följande appar finns tillgängliga" -#: core/doctype/user/user.py:753 +#: core/doctype/user/user.py:768 msgid "Newly created user {0} has no roles enabled." msgstr "Nyskapad användare {0} har inga roller aktiverade." @@ -16173,7 +16229,7 @@ msgstr "Nyhetsbrev ska ha minst en mottagare" msgid "Newsletters" msgstr "Nyhetsbrev" -#: public/js/frappe/form/form_tour.js:318 +#: public/js/frappe/form/form_tour.js:14 public/js/frappe/form/form_tour.js:324 #: public/js/frappe/web_form/web_form.js:91 #: public/js/onboarding_tours/onboarding_tours.js:15 #: public/js/onboarding_tours/onboarding_tours.js:240 @@ -16323,7 +16379,7 @@ msgstr "Inga E-post" msgid "No Entry for the User {0} found within LDAP!" msgstr "Ingen Konto för Användare {0} hittades i LDAP!" -#: public/js/frappe/widgets/chart_widget.js:366 +#: public/js/frappe/widgets/chart_widget.js:367 msgid "No Filters Set" msgstr "Inga Filter Angivna" @@ -16401,7 +16457,7 @@ msgstr "Inga Träffar" msgid "No Results found" msgstr "Inga Träffar" -#: core/doctype/user/user.py:754 +#: core/doctype/user/user.py:769 msgid "No Roles Specified" msgstr "Inga Roller Specificerade" @@ -16429,7 +16485,7 @@ msgstr "Inga aktiviteter att visa" msgid "No address added yet." msgstr "Ingen adress upplagd än" -#: email/doctype/notification/notification.js:180 +#: email/doctype/notification/notification.js:203 msgid "No alerts for today" msgstr "Inga varningar för idag" @@ -16556,11 +16612,11 @@ msgstr "Antal Rader (Max 500)" msgid "No of Sent SMS" msgstr "Antal Skickade SMS" -#: __init__.py:1126 client.py:109 client.py:151 +#: __init__.py:1132 client.py:109 client.py:151 msgid "No permission for {0}" msgstr "Ingen Behörighet för {0}" -#: public/js/frappe/form/form.js:1137 +#: public/js/frappe/form/form.js:1141 msgctxt "{0} = verb, {1} = object" msgid "No permission to '{0}' {1}" msgstr "Behörigheter saknas att '{0}' {1}" @@ -16585,7 +16641,7 @@ msgstr "Inga poster finns i {0}" msgid "No records tagged." msgstr "Inga taggade poster" -#: public/js/frappe/data_import/data_exporter.js:224 +#: public/js/frappe/data_import/data_exporter.js:225 msgid "No records will be exported" msgstr "Inga poster kommer att exporteras" @@ -16609,7 +16665,7 @@ msgstr "Ingen {0} Hittades" msgid "No {0} found" msgstr "Ingen {0} Hittades" -#: public/js/frappe/list/list_view.js:469 +#: public/js/frappe/list/list_view.js:466 msgid "No {0} found with matching filters. Clear filters to see all {0}." msgstr "{0} hittades med vald filter. Rensa filter för att se alla {0}." @@ -16651,7 +16707,7 @@ msgstr "Normaliserade Kopior" msgid "Normalized Query" msgstr "Normaliserad Fråga" -#: core/doctype/user/user.py:959 templates/includes/login/login.js:257 +#: core/doctype/user/user.py:974 templates/includes/login/login.js:257 #: utils/oauth.py:265 msgid "Not Allowed" msgstr "Ej Tillåtet" @@ -16698,7 +16754,7 @@ msgstr "Ej Länkad till någon post" msgid "Not Nullable" msgstr "Ej Nullbar" -#: __init__.py:1018 app.py:357 desk/calendar.py:26 geo/utils.py:97 +#: __init__.py:1024 app.py:357 desk/calendar.py:26 geo/utils.py:97 #: public/js/frappe/web_form/webform_script.js:15 #: website/doctype/web_form/web_form.py:602 #: website/page_renderers/not_permitted_page.py:20 www/login.py:181 @@ -16750,7 +16806,7 @@ msgstr "Ej Angiven" msgid "Not a valid Comma Separated Value (CSV File)" msgstr "Ej giltig Komma Separerad Värde (CSV Fil)" -#: core/doctype/user/user.py:235 +#: core/doctype/user/user.py:240 msgid "Not a valid User Image." msgstr "Ej giltig Användare Bild." @@ -16770,7 +16826,7 @@ msgstr "Inte Aktiv" msgid "Not allowed for {0}: {1}" msgstr "Ej tillåtet för {0}: {1}" -#: email/doctype/notification/notification.py:392 +#: email/doctype/notification/notification.py:440 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "Ej Tillåtet att bifoga {0} dokument, aktivera \"Tillåt Utskrift\" för {0} i Utskrift Inställningar" @@ -16952,6 +17008,18 @@ msgstr "Avisering Prenumererad Dokument" msgid "Notification sent to" msgstr "Avisering skickad till" +#: email/doctype/notification/notification.py:345 +msgid "Notification: customer {0} has no Mobile number set" +msgstr "Meddelande: kund {0} har inget mobil nummer angivet" + +#: email/doctype/notification/notification.py:331 +msgid "Notification: document {0} has no {1} number set (field: {2})" +msgstr "Meddelande: dokument {0} har inget {1} nummer angivet (fält: {2})" + +#: email/doctype/notification/notification.py:340 +msgid "Notification: user {0} has no Mobile number set" +msgstr "Meddelande: användare {0} har inget mobil nummer angivet" + #. Label of the notifications (Check) field in DocType 'Role' #: core/doctype/role/role.json #: public/js/frappe/ui/notifications/notifications.js:50 @@ -17156,7 +17224,7 @@ msgstr "OAuth Inställningar" msgid "OAuth Scope" msgstr "OAuth omfattning" -#: email/doctype/email_account/email_account.js:182 +#: email/doctype/email_account/email_account.js:211 msgid "OAuth has been enabled but not authorised. Please use \"Authorise API Access\" button to do the same." msgstr "OAuth är aktiverad men inte auktoriserad. Använd \"Auktorisera API Tillgång\" knapp för att göra detta." @@ -17180,11 +17248,11 @@ msgstr "OTP App" msgid "OTP Issuer Name" msgstr "OTP Utgivarens Namn" -#: twofactor.py:461 +#: twofactor.py:445 msgid "OTP Secret Reset - {0}" msgstr "OTP Hemlighet Återställning - {0}" -#: twofactor.py:480 +#: twofactor.py:464 msgid "OTP Secret has been reset. Re-registration will be required on next login." msgstr "OTP Hemlighet är återställd. Omgistrering erfodras vid nästa inloggning." @@ -17356,7 +17424,7 @@ msgstr "En av de underordnade sidorna med namnet {0} finns redan i sektion {1}. msgid "Only 200 inserts allowed in one request" msgstr "Endast 200 infogningar tillåts per begäran" -#: email/doctype/email_queue/email_queue.py:81 +#: email/doctype/email_queue/email_queue.py:82 msgid "Only Administrator can delete Email Queue" msgstr "Endast Administratör kan radera E-post Kö" @@ -17520,7 +17588,7 @@ msgstr "Öppna dialogruta med erfodrade fält för att snabbt skapa ny post" msgid "Open a module or tool" msgstr "Öppna modul eller verktyg" -#: public/js/frappe/list/list_view.js:1214 +#: public/js/frappe/list/list_view.js:1251 msgctxt "Description of a list view shortcut" msgid "Open list item" msgstr "Öppna List Post" @@ -17695,10 +17763,10 @@ msgstr "Ursprung Värde" msgid "Other" msgstr "Annat" -#. Label of the outgoing_smtp_tab (Tab Break) field in DocType 'Email Account' +#. Label of the outgoing_tab (Tab Break) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -msgid "Outgoing (SMTP)" -msgstr "Utgående (SMTP)" +msgid "Outgoing" +msgstr "Utgående" #. Label of the outgoing_mail_settings (Section Break) field in DocType 'Email #. Account' @@ -18113,11 +18181,11 @@ msgstr "Passiv" msgid "Password" msgstr "Lösenord" -#: core/doctype/user/user.py:1022 +#: core/doctype/user/user.py:1037 msgid "Password Email Sent" msgstr "Lösenord E-post Skickad" -#: core/doctype/user/user.py:406 +#: core/doctype/user/user.py:412 msgid "Password Reset" msgstr "Lösenord Återställning" @@ -18139,7 +18207,7 @@ msgstr "Lösenord ändrad." msgid "Password for Base DN" msgstr "Lösenord för Base DN" -#: email/doctype/email_account/email_account.py:172 +#: email/doctype/email_account/email_account.py:182 msgid "Password is required or select Awaiting Password" msgstr "Lösenord erfodras eller välj Väntar på Lösenord" @@ -18151,7 +18219,7 @@ msgstr "Lösenord saknas i E-post Konto" msgid "Password not found for {0} {1} {2}" msgstr "Lösenord hittades inte för {0} {1} {2}" -#: core/doctype/user/user.py:1021 +#: core/doctype/user/user.py:1036 msgid "Password reset instructions have been sent to {}'s email" msgstr "Instruktioner för återställning av lösenord är skickade till {}'s e-post" @@ -18163,7 +18231,7 @@ msgstr "Lösenord angiven" msgid "Password size exceeded the maximum allowed size" msgstr "Lösenord längd överskred maximum tillåten längd." -#: core/doctype/user/user.py:817 +#: core/doctype/user/user.py:832 msgid "Password size exceeded the maximum allowed size." msgstr "Lösenord längd överskred maximum tillåten längd." @@ -18301,15 +18369,15 @@ msgstr "Behörighet Nivå" msgid "Permanent" msgstr "Permanent" -#: public/js/frappe/form/form.js:1023 +#: public/js/frappe/form/form.js:1027 msgid "Permanently Cancel {0}?" msgstr "Avbryt {0}?" -#: public/js/frappe/form/form.js:1069 +#: public/js/frappe/form/form.js:1073 msgid "Permanently Discard {0}?" msgstr "Annullera {0}? " -#: public/js/frappe/form/form.js:853 +#: public/js/frappe/form/form.js:857 msgid "Permanently Submit {0}?" msgstr "Godkänn {0}?" @@ -18496,6 +18564,10 @@ msgstr "Vanlig Text" msgid "Plant" msgstr "Fastighet" +#: email/doctype/email_account/email_account.py:535 +msgid "Please Authorize OAuth for Email Account {0}" +msgstr "Auktorisera OAuth för E-post Konto {0}" + #: email/oauth.py:29 msgid "Please Authorize OAuth for Email Account {}" msgstr "Vänligen Auktorisera OAuth för E-post Konto {}" @@ -18524,7 +18596,7 @@ msgstr "Lägg till ämne i E-post" msgid "Please add a valid comment." msgstr "Lägg till giltig kommentar." -#: core/doctype/user/user.py:1004 +#: core/doctype/user/user.py:1019 msgid "Please ask your administrator to verify your sign-up" msgstr "Be Administratör att verifiera din registrering" @@ -18556,7 +18628,7 @@ msgstr "Kontrollera filter värden angivna för Översikt Panel Diagram: {}" msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "Kontrollera värde för uppsättning 'Hämta från' för fält {0}" -#: core/doctype/user/user.py:1002 +#: core/doctype/user/user.py:1017 msgid "Please check your email for verification" msgstr "Kontrollera din E-post för verifiering" @@ -18838,11 +18910,11 @@ msgstr "Konfigurera SMS före du anger den som Autentisering Sätt via SMS Inst msgid "Please setup a message first" msgstr "Försäljning Order Meddelande" -#: email/doctype/email_account/email_account.py:407 +#: email/doctype/email_account/email_account.py:423 msgid "Please setup default Email Account from Settings > Email Account" msgstr "Ange Standard E-Post Konto från Inställningar > E-post Konto" -#: core/doctype/user/user.py:371 +#: core/doctype/user/user.py:377 msgid "Please setup default outgoing Email Account from Settings > Email Account" msgstr "Ange Standard E-post Konto från Inställningar > E-post > E-post Konto" @@ -19123,6 +19195,7 @@ msgstr "Förhandsgranskning av genererade namn" msgid "Preview:" msgstr "Förhandsgranska:" +#: public/js/frappe/form/form_tour.js:15 #: public/js/frappe/web_form/web_form.js:95 #: public/js/onboarding_tours/onboarding_tours.js:16 #: templates/includes/slideshow.html:34 @@ -19144,7 +19217,7 @@ msgstr "Föregående Dokument" msgid "Previous Hash" msgstr "Föregående Hash" -#: public/js/frappe/form/form.js:2217 +#: public/js/frappe/form/form.js:2222 msgid "Previous Submission" msgstr "Föregående Godkännande" @@ -19184,9 +19257,11 @@ msgstr "Primär nyckel för doctype {0} kan inte ändras eftersom det finns befi #. Label of the print (Check) field in DocType 'Custom DocPerm' #. Label of the print (Check) field in DocType 'DocPerm' +#. Label of the print (Check) field in DocType 'User Document Type' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json #: core/doctype/success_action/success_action.js:56 +#: core/doctype/user_document_type/user_document_type.json #: printing/page/print/print.js:65 public/js/frappe/form/success_action.js:81 #: public/js/frappe/form/templates/print_layout.html:46 #: public/js/frappe/form/toolbar.js:332 public/js/frappe/form/toolbar.js:344 @@ -19197,7 +19272,7 @@ msgstr "Primär nyckel för doctype {0} kan inte ändras eftersom det finns befi msgid "Print" msgstr "Utskrift" -#: public/js/frappe/list/list_view.js:1918 +#: public/js/frappe/list/list_view.js:1972 msgctxt "Button in list view actions menu" msgid "Print" msgstr "Utskrift" @@ -19457,7 +19532,7 @@ msgstr "Fortsätt Ändå" msgid "Processing" msgstr "Behandlar" -#: email/doctype/email_queue/email_queue.py:434 +#: email/doctype/email_queue/email_queue.py:447 msgid "Processing..." msgstr "Behandlar..." @@ -19593,7 +19668,7 @@ msgstr "Publicerad" msgid "Publishing Dates" msgstr "Publicering Datum" -#: email/doctype/email_account/email_account.js:159 +#: email/doctype/email_account/email_account.js:179 msgid "Pull Emails" msgstr "Hämta E-post" @@ -19940,12 +20015,12 @@ msgstr "Direkt Utskrift Inställningar " msgid "Re-Run in Console" msgstr "Kör igen i Konsol" -#: email/doctype/email_account/email_account.py:669 +#: email/doctype/email_account/email_account.py:720 msgid "Re:" msgstr "Sv:" #: core/doctype/communication/communication.js:268 -#: public/js/frappe/form/footer/form_timeline.js:587 +#: public/js/frappe/form/footer/form_timeline.js:589 #: public/js/frappe/views/communication.js:355 msgid "Re: {0}" msgstr "Sv: {0}" @@ -20408,12 +20483,12 @@ msgid "Referrer" msgstr "Referens" #: printing/page/print/print.js:73 public/js/frappe/desk.js:134 -#: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1196 +#: public/js/frappe/desk.js:533 public/js/frappe/form/form.js:1200 #: public/js/frappe/form/templates/print_layout.html:6 #: public/js/frappe/list/base_list.js:66 #: public/js/frappe/views/reports/query_report.js:1629 #: public/js/frappe/views/treeview.js:475 -#: public/js/frappe/widgets/chart_widget.js:290 +#: public/js/frappe/widgets/chart_widget.js:291 #: public/js/frappe/widgets/number_card_widget.js:324 msgid "Refresh" msgstr "Uppdatera" @@ -20440,7 +20515,7 @@ msgstr "Uppdatera Google Sheet" msgid "Refresh Token" msgstr "Uppdatera Token" -#: public/js/frappe/list/list_view.js:507 +#: public/js/frappe/list/list_view.js:504 msgctxt "Document count in list view" msgid "Refreshing" msgstr "Uppdaterar" @@ -20450,7 +20525,7 @@ msgstr "Uppdaterar" msgid "Refreshing..." msgstr "Uppdaterar..." -#: core/doctype/user/user.py:966 +#: core/doctype/user/user.py:981 msgid "Registered but disabled" msgstr "Registrerad men inaktiverad" @@ -20667,7 +20742,7 @@ msgstr "Besvarad" #. Label of the reply (Text Editor) field in DocType 'Discussion Reply' #: core/doctype/communication/communication.js:57 -#: public/js/frappe/form/footer/form_timeline.js:550 +#: public/js/frappe/form/footer/form_timeline.js:552 #: website/doctype/discussion_reply/discussion_reply.json msgid "Reply" msgstr "Svara" @@ -20993,7 +21068,7 @@ msgstr "Återställ Alla Anpassningar" msgid "Reset Changes" msgstr "Återställ ändringar" -#: public/js/frappe/widgets/chart_widget.js:305 +#: public/js/frappe/widgets/chart_widget.js:306 msgid "Reset Chart" msgstr "Återställ Diagram" @@ -21341,7 +21416,7 @@ msgstr "Roll Behörigheter" msgid "Role Permissions Manager" msgstr "Roll Behörigheter Hanterare" -#: public/js/frappe/list/list_view.js:1695 +#: public/js/frappe/list/list_view.js:1749 msgctxt "Button in list view menu" msgid "Role Permissions Manager" msgstr "Roll Behörigheter Hanterare" @@ -21373,7 +21448,7 @@ msgstr "Roll Profiler " msgid "Role and Level" msgstr "Roll och Nivå" -#: core/doctype/user/user.py:316 +#: core/doctype/user/user.py:322 msgid "Role has been set as per the user type {0}" msgstr "Rollen angiven enligt användare typ {0}" @@ -21674,7 +21749,7 @@ msgstr "SMS skickad till följande nummer: {0}" msgid "SMS was not sent. Please contact Administrator." msgstr "SMS inte skickad. Kontakta Administratör." -#: email/doctype/email_account/email_account.py:189 +#: email/doctype/email_account/email_account.py:205 msgid "SMTP Server is required" msgstr "SMTP Server erfodras" @@ -21772,7 +21847,7 @@ msgstr "Lördag" #: email/doctype/notification/notification.json #: printing/page/print/print.js:856 #: printing/page/print_format_builder/print_format_builder.js:160 -#: public/js/frappe/form/footer/form_timeline.js:661 +#: public/js/frappe/form/footer/form_timeline.js:663 #: public/js/frappe/form/quick_entry.js:161 #: public/js/frappe/list/list_settings.js:36 #: public/js/frappe/list/list_settings.js:244 @@ -21826,7 +21901,7 @@ msgstr "Spara Filter" msgid "Save on Completion" msgstr "Spara Vid Klar" -#: public/js/frappe/form/form_tour.js:289 +#: public/js/frappe/form/form_tour.js:295 msgid "Save the document." msgstr "Spara Dokument ==>" @@ -22169,7 +22244,7 @@ msgstr "Visa All Aktivitet" msgid "See all past reports." msgstr "Visa alla tidigare rapporter." -#: public/js/frappe/form/form.js:1230 +#: public/js/frappe/form/form.js:1234 #: website/doctype/contact_us_settings/contact_us_settings.js:4 msgid "See on Website" msgstr "Visapå Webbplats" @@ -22228,7 +22303,7 @@ msgstr "Visning Tabell" msgid "Select" msgstr "Välj i Listan" -#: public/js/frappe/data_import/data_exporter.js:148 +#: public/js/frappe/data_import/data_exporter.js:149 #: public/js/frappe/form/controls/multicheck.js:166 msgid "Select All" msgstr "Välj Alla" @@ -22316,11 +22391,11 @@ msgstr "Välj Fält..." msgid "Select Fields" msgstr "Välj Fält" -#: public/js/frappe/data_import/data_exporter.js:146 +#: public/js/frappe/data_import/data_exporter.js:147 msgid "Select Fields To Insert" msgstr "Välj Fält att Infoga" -#: public/js/frappe/data_import/data_exporter.js:147 +#: public/js/frappe/data_import/data_exporter.js:148 msgid "Select Fields To Update" msgstr "Välj Fält att Uppdatera" @@ -22353,7 +22428,7 @@ msgstr "Välj Språk" msgid "Select List View" msgstr "Välj List Vy" -#: public/js/frappe/data_import/data_exporter.js:157 +#: public/js/frappe/data_import/data_exporter.js:158 msgid "Select Mandatory" msgstr "Välj Erfordrad" @@ -22435,7 +22510,7 @@ msgstr "Välj giltig Avsändar Fält att skapa dokument från E-post" msgid "Select a valid Subject field for creating documents from Email" msgstr "Välj giltig Ämne Fält att skapa dokument från E-post" -#: public/js/frappe/form/form_tour.js:315 +#: public/js/frappe/form/form_tour.js:321 msgid "Select an Image" msgstr "Välj Bild" @@ -22457,13 +22532,13 @@ msgstr "Välj minst en post för utskrift" msgid "Select atleast 2 actions" msgstr "Välj minst två åtgärder" -#: public/js/frappe/list/list_view.js:1228 +#: public/js/frappe/list/list_view.js:1265 msgctxt "Description of a list view shortcut" msgid "Select list item" msgstr "Välj List Artikel" -#: public/js/frappe/list/list_view.js:1180 -#: public/js/frappe/list/list_view.js:1196 +#: public/js/frappe/list/list_view.js:1217 +#: public/js/frappe/list/list_view.js:1233 msgctxt "Description of a list view shortcut" msgid "Select multiple list items" msgstr "Välj flera List Artiklar" @@ -22905,6 +22980,14 @@ msgstr "Session Förfaller (Tid av Inaktivitet)" msgid "Session Expiry must be in format {0}" msgstr "Session Förfallo tid måste vara i format {0}" +#: desk/doctype/dashboard_chart/dashboard_chart.js:400 +#: desk/doctype/dashboard_chart/dashboard_chart.js:487 +#: desk/doctype/number_card/number_card.js:295 +#: desk/doctype/number_card/number_card.js:387 +#: public/js/frappe/widgets/chart_widget.js:407 +msgid "Set" +msgstr "Ange" + #: public/js/frappe/ui/filters/filter.js:569 msgctxt "Field value is set" msgid "Set" @@ -22936,7 +23019,7 @@ msgstr "Ange Dynamisk Filter" msgid "Set Filters" msgstr "Ange Filter" -#: public/js/frappe/widgets/chart_widget.js:395 +#: public/js/frappe/widgets/chart_widget.js:396 #: public/js/frappe/widgets/quick_list_widget.js:104 msgid "Set Filters for {0}" msgstr "Ange Filter för {0}" @@ -23025,6 +23108,10 @@ msgstr "Ange som Standard Tema" msgid "Set by user" msgstr "Anges av Användare" +#: public/js/frappe/utils/dashboard_utils.js:162 +msgid "Set dynamic filter values in JavaScript for the required fields here." +msgstr "Ange dynamiska filtervärden i JavaScript för erfordrade fält här." + #. Description of the 'Precision' (Select) field in DocType 'DocField' #. Description of the 'Precision' (Select) field in DocType 'Custom Field' #. Description of the 'Precision' (Select) field in DocType 'Customize Form @@ -23204,9 +23291,11 @@ msgstr "Ange Nummer Serie för Transaktioner" #. Label of the share (Check) field in DocType 'Custom DocPerm' #. Label of the share (Check) field in DocType 'DocPerm' #. Label of the share (Check) field in DocType 'DocShare' +#. Label of the share (Check) field in DocType 'User Document Type' #. Option for the 'Type' (Select) field in DocType 'Notification Log' #: core/doctype/custom_docperm/custom_docperm.json #: core/doctype/docperm/docperm.json core/doctype/docshare/docshare.json +#: core/doctype/user_document_type/user_document_type.json #: desk/doctype/notification_log/notification_log.json #: public/js/frappe/form/templates/form_sidebar.html:110 msgid "Share" @@ -23318,7 +23407,7 @@ msgstr "Visa Dokument" msgid "Show Error" msgstr "Visa Fel" -#: public/js/frappe/form/layout.js:561 +#: public/js/frappe/form/layout.js:563 msgid "Show Fieldname (click to copy on clipboard)" msgstr "Visa Fältnamn (klicka för att kopiera till urklipp)" @@ -23436,7 +23525,7 @@ msgid "Show Sidebar" msgstr "Visa Sidofält" #: public/js/frappe/list/list_sidebar.html:66 -#: public/js/frappe/list/list_view.js:1611 +#: public/js/frappe/list/list_view.js:1665 msgid "Show Tags" msgstr "Visa Taggar" @@ -23483,7 +23572,7 @@ msgstr "Visa konto borttagning länk på Mitt Konto sida" msgid "Show all Versions" msgstr "Visa alla versioner" -#: public/js/frappe/form/footer/form_timeline.js:67 +#: public/js/frappe/form/footer/form_timeline.js:69 msgid "Show all activity" msgstr "Visa All Aktivitet" @@ -23523,7 +23612,7 @@ msgstr "Visa i Filter" msgid "Show link to document" msgstr "Visa Länk till Dokument" -#: public/js/frappe/form/layout.js:255 public/js/frappe/form/layout.js:273 +#: public/js/frappe/form/layout.js:257 public/js/frappe/form/layout.js:275 msgid "Show more details" msgstr "Visa fler detaljer" @@ -23577,7 +23666,7 @@ msgstr "Sidofält och Kommentarer" msgid "Sign Up and Confirmation" msgstr "Registrering och Bekräftelse" -#: core/doctype/user/user.py:959 +#: core/doctype/user/user.py:974 msgid "Sign Up is disabled" msgstr "Registrering är inaktiverad" @@ -23693,7 +23782,7 @@ msgstr "Hoppar över Namnlös Kolumn" msgid "Skipping column {0}" msgstr "Hoppar över Kolumn {0}" -#: modules/utils.py:171 +#: modules/utils.py:175 msgid "Skipping fixture syncing for doctype {0} from file {1}" msgstr "Hoppar över fixture synkronisering för doctype {0} från fil {1}" @@ -23975,6 +24064,10 @@ msgstr "Standard DocType kan inte ha standard utskrift mall, använd Anpassa For msgid "Standard Not Set" msgstr "Standard Ej Angiven" +#: core/page/permission_manager/permission_manager.js:125 +msgid "Standard Permissions" +msgstr "Standard Behörigheter" + #: printing/doctype/print_format/print_format.py:74 msgid "Standard Print Format cannot be updated" msgstr "Standard Utskrift Format kan inte uppdateras" @@ -24377,7 +24470,7 @@ msgstr "Godkännande Kö" msgid "Submit" msgstr "Godkänn" -#: public/js/frappe/list/list_view.js:1985 +#: public/js/frappe/list/list_view.js:2039 msgctxt "Button in list view actions menu" msgid "Submit" msgstr "Godkänn" @@ -24430,11 +24523,11 @@ msgstr "Godkänn vid Skapande" msgid "Submit this document to complete this step." msgstr "Godkänn detta dokument för att slutföra detta steg." -#: public/js/frappe/form/form.js:1216 +#: public/js/frappe/form/form.js:1220 msgid "Submit this document to confirm" msgstr "Tryck på Spara/Godkänn för att genomföra." -#: public/js/frappe/list/list_view.js:1990 +#: public/js/frappe/list/list_view.js:2044 msgctxt "Title of confirmation dialog" msgid "Submit {0} documents?" msgstr "Godkänn {0} dokument?" @@ -24584,7 +24677,7 @@ msgstr "Föreslå Optimeringar" msgid "Suggested Indexes" msgstr "Föreslagen Indexering" -#: core/doctype/user/user.py:674 +#: core/doctype/user/user.py:689 msgid "Suggested Username: {0}" msgstr "Föreslagen Användarnamn: {0}" @@ -25107,7 +25200,7 @@ msgstr "Mall Varningar" msgid "Templates" msgstr "Mallar" -#: core/doctype/user/user.py:970 +#: core/doctype/user/user.py:985 msgid "Temporarily Disabled" msgstr "Tillfälligt Inaktiverad" @@ -25259,7 +25352,11 @@ msgstr "Kolumn {0} har {1} olika datum format. Automatiskt ange {2} som standard msgid "The comment cannot be empty" msgstr "Kommentar kan inte vara tom" -#: public/js/frappe/list/list_view.js:630 +#: templates/emails/workflow_action.html:9 +msgid "The contents of this email are strictly confidential. Please do not forward this email to anyone." +msgstr "Innehållet i detta e-post meddelande är strikt konfidentiellt. Vänligen vidarebefordra inte detta e-post meddelande till någon." + +#: public/js/frappe/list/list_view.js:629 msgid "The count shown is an estimated count. Click here to see the accurate count." msgstr "Antal som visas är uppskattat antal. Klicka här för att se exakt antal." @@ -25360,11 +25457,11 @@ msgstr "Projekt Nummer erhålln från Google Cloud Console under
    " -#: core/doctype/user/user.py:930 +#: core/doctype/user/user.py:945 msgid "The reset password link has been expired" msgstr "Länk för återställning av lösenord har upphört att gälla" -#: core/doctype/user/user.py:932 +#: core/doctype/user/user.py:947 msgid "The reset password link has either been used before or is invalid" msgstr "Länk för återställning av lösenord har antingen använts tidigare eller är ogiltig" @@ -25402,7 +25499,7 @@ msgstr "Totalt antal användar dokument typer är passerad." msgid "The user from this field will be rewarded points" msgstr "Användare från detta fält kommer att belönas med poäng" -#: public/js/frappe/form/controls/data.js:24 +#: public/js/frappe/form/controls/data.js:25 msgid "The value you pasted was {0} characters long. Max allowed characters is {1}." msgstr "Antal tecken som klistrades in var {0}. Max tillåtet antal är {1}." @@ -25563,7 +25660,7 @@ msgstr "Detta Anslag Tavla kommer att vara privat" msgid "This action is irreversible. Do you wish to continue?" msgstr "Denna åtgärd är oåterkallelig. Vill du fortsätta?" -#: __init__.py:1014 +#: __init__.py:1020 msgid "This action is only allowed for {}" msgstr "Åtgärd är endast tillåten för {}" @@ -25609,11 +25706,11 @@ msgstr "Dokument har ändrats efter att e-post meddelande skickades." msgid "This document has been reverted" msgstr "Dokument är återställd" -#: public/js/frappe/form/form.js:1304 +#: public/js/frappe/form/form.js:1308 msgid "This document has unsaved changes which might not appear in final PDF.
    Consider saving the document before printing." msgstr "Detta dokument har osparade ändringar som kanske inte visas i slutlig PDF fil.
    Spara dokument innan utskrift." -#: public/js/frappe/form/form.js:1097 +#: public/js/frappe/form/form.js:1101 msgid "This document is already amended, you cannot ammend it again" msgstr "Detta dokument är redan ändrad, du kan inte ändra det igen" @@ -25650,7 +25747,7 @@ msgstr "Detta fält visas endast om fält namn definieras här har värde eller msgid "This file is public. It can be accessed without authentication." msgstr "Denna fil är publik. Den kan nås utan autentisering." -#: public/js/frappe/form/form.js:1194 +#: public/js/frappe/form/form.js:1198 msgid "This form has been modified after you have loaded it" msgstr "Denna form har ändrats efter öppnande" @@ -25797,7 +25894,7 @@ msgstr "Detta återställer Formulär Tur och visar den för alla användare. Ä msgid "This will terminate the job immediately and might be dangerous, are you sure? " msgstr "Detta avslutar jobb omedelbart och kan vara farligt, är du säker?" -#: core/doctype/user/user.py:1190 +#: core/doctype/user/user.py:1205 msgid "Throttled" msgstr "Strypt" @@ -26151,7 +26248,7 @@ msgstr "Hantera Tredje Part Appar" msgid "To print output use print(text)" msgstr "För att skriva ut, använd print(text)" -#: core/doctype/user_type/user_type.py:295 +#: core/doctype/user_type/user_type.py:292 msgid "To set the role {0} in the user {1}, kindly set the {2} field as {3} in one of the {4} record." msgstr "För att ange roll {0} för användare {1}, ange {2}-fält som {3} i en av {4}-poster." @@ -26218,7 +26315,7 @@ msgstr "Växla Rutnät Vy" msgid "Toggle Sidebar" msgstr "Växla Sidofält" -#: public/js/frappe/list/list_view.js:1726 +#: public/js/frappe/list/list_view.js:1780 msgctxt "Button in list view menu" msgid "Toggle Sidebar" msgstr "Växla Sidofält" @@ -26265,7 +26362,7 @@ msgstr "För Många Begäran" msgid "Too many changes to database in single action." msgstr "För många ändringar i databas i en enda åtgärd." -#: core/doctype/user/user.py:971 +#: core/doctype/user/user.py:986 msgid "Too many users signed up recently, so the registration is disabled. Please try back in an hour" msgstr "Alltför många Användare registrerade sig nyligen, så registrering är inaktiverad. Försök igen om en timme" @@ -26771,7 +26868,7 @@ msgstr "Kan inte ladda: {0}" msgid "Unable to open attached file. Did you export it as CSV?" msgstr "Kan inte öppna bifogad fil. Är den exporterad som CSV?" -#: core/doctype/file/utils.py:97 core/doctype/file/utils.py:129 +#: core/doctype/file/utils.py:98 core/doctype/file/utils.py:130 msgid "Unable to read file format for {0}" msgstr "Kan inte läsa fil format för {0}" @@ -26880,7 +26977,7 @@ msgstr "Oläst Avisering Skickad" msgid "Unsafe SQL query" msgstr "Osäker SQL Fråga" -#: public/js/frappe/data_import/data_exporter.js:158 +#: public/js/frappe/data_import/data_exporter.js:159 #: public/js/frappe/form/controls/multicheck.js:166 msgid "Unselect All" msgstr "Avmarkera Alla" @@ -27050,7 +27147,7 @@ msgctxt "Freeze message while updating a document" msgid "Updating" msgstr "Uppdaterar" -#: email/doctype/email_queue/email_queue.py:433 +#: email/doctype/email_queue/email_queue.py:446 msgid "Updating Email Queue Statuses. The emails will be picked up in the next scheduled run." msgstr "Uppdatera E-post kö status. E-post kommer att hämtas vid nästa schemalagda körning." @@ -27378,7 +27475,7 @@ msgstr "Användare" msgid "User Id Field" msgstr "Användar ID Fält" -#: core/doctype/user_type/user_type.py:287 +#: core/doctype/user_type/user_type.py:284 msgid "User Id Field is mandatory in the user type {0}" msgstr "Fält Användare ID erfodras i användare typ {0}" @@ -27408,7 +27505,7 @@ msgstr "Användare Behörighet" msgid "User Permissions" msgstr "Användare Behörigheter" -#: public/js/frappe/list/list_view.js:1684 +#: public/js/frappe/list/list_view.js:1738 msgctxt "Button in list view menu" msgid "User Permissions" msgstr "Användare Behörigheter" @@ -27515,7 +27612,7 @@ msgstr "Användare erfodras för Delad Mapp" msgid "User must always select" msgstr "Användare måste altid välja" -#: model/delete_doc.py:235 +#: model/delete_doc.py:244 msgid "User not allowed to delete {0}: {1}" msgstr "Användare är inte tillåten radera {0}: {1}" @@ -27531,15 +27628,15 @@ msgstr "Användare med E-post {0} finns inte" msgid "User with email: {0} does not exist in the system. Please ask 'System Administrator' to create the user for you." msgstr "Användare med E-post: {0} finns inte. Be 'System Administratör' om hjälp." -#: core/doctype/user/user.py:485 +#: core/doctype/user/user.py:491 msgid "User {0} cannot be deleted" msgstr "Användare {0} kan inte raderas" -#: core/doctype/user/user.py:280 +#: core/doctype/user/user.py:285 msgid "User {0} cannot be disabled" msgstr "Användare {0} kan inte inaktiveras" -#: core/doctype/user/user.py:556 +#: core/doctype/user/user.py:571 msgid "User {0} cannot be renamed" msgstr "Användare {0} kan inte byta namn" @@ -27560,7 +27657,7 @@ msgstr "Användare {0} har inte behörighet att skapa Arbetsyta." msgid "User {0} has requested for data deletion" msgstr "Användare {0} begärde radering av data" -#: core/doctype/user/user.py:1319 +#: core/doctype/user/user.py:1334 msgid "User {0} impersonated as {1}" msgstr "Användare {0} efterliknade som {1}" @@ -27588,7 +27685,7 @@ msgstr "Användare Info URI" msgid "Username" msgstr "Användare Namn" -#: core/doctype/user/user.py:641 +#: core/doctype/user/user.py:656 msgid "Username {0} already exists" msgstr "Användare Namn {0} finns redan" @@ -27651,6 +27748,12 @@ msgstr "Giltig e-post och namn erfodras" msgid "Validate Field" msgstr "Validera Fält" +#. Label of the validate_frappe_mail_settings (Button) field in DocType 'Email +#. Account' +#: email/doctype/email_account/email_account.json +msgid "Validate Frappe Mail Settings" +msgstr "Validera Frappe Mail Inställningar" + #. Label of the validate_ssl_certificate (Check) field in DocType 'Email #. Account' #. Label of the validate_ssl_certificate (Check) field in DocType 'Email @@ -27789,7 +27892,7 @@ msgstr "Värde Ändrad " msgid "Verdana" msgstr "Verdana" -#: twofactor.py:357 +#: twofactor.py:352 msgid "Verfication Code" msgstr "Verifiering Kod" @@ -27810,11 +27913,11 @@ msgstr "Verifiering Kod är skickad till din E-post." msgid "Verified" msgstr "Verifierad" -#: public/js/frappe/ui/messages.js:350 +#: public/js/frappe/ui/messages.js:352 msgid "Verify" msgstr "Verifiera" -#: public/js/frappe/ui/messages.js:349 +#: public/js/frappe/ui/messages.js:351 msgid "Verify Password" msgstr "Verifiera Lösenord" @@ -28187,7 +28290,7 @@ msgstr "Webhook URL" #. Group in Module Def's connections #. Name of a Workspace #: core/doctype/module_def/module_def.json -#: email/doctype/newsletter/newsletter.py:449 +#: email/doctype/newsletter/newsletter.py:453 #: public/js/frappe/ui/toolbar/about.js:8 #: website/workspace/website/website.json msgid "Website" @@ -28425,11 +28528,11 @@ msgstr "Välkommen URL" msgid "Welcome Workspace" msgstr "Välkommen Arbetsyta" -#: core/doctype/user/user.py:363 +#: core/doctype/user/user.py:369 msgid "Welcome email sent" msgstr "Välkomst E-post skickad" -#: core/doctype/user/user.py:424 +#: core/doctype/user/user.py:430 msgid "Welcome to {0}" msgstr "Välkommen till {0}" @@ -28852,7 +28955,7 @@ msgctxt "Name of the current user. For example: You edited this 5 hours ago." msgid "You" msgstr "Du" -#: public/js/frappe/form/footer/form_timeline.js:462 +#: public/js/frappe/form/footer/form_timeline.js:464 msgid "You Liked" msgstr "Du Gillade" @@ -28916,7 +29019,7 @@ msgstr "Du har inte behörighet att komma åt denna sida utan inloggning." msgid "You are not permitted to access this page." msgstr "Du har inte behörighet att komma åt den här sidan." -#: __init__.py:933 +#: __init__.py:939 msgid "You are not permitted to access this resource." msgstr "Du har inte behörighet att komma åt denna resurs." @@ -28928,11 +29031,11 @@ msgstr "Du följer nu detta dokument och kommer att få dagliga uppdateringar vi msgid "You are only allowed to update order, do not remove or add apps." msgstr "Du får bara uppdatera ordning, inte ta bort eller lägga till appar." -#: email/doctype/email_account/email_account.js:216 +#: email/doctype/email_account/email_account.js:245 msgid "You are selecting Sync Option as ALL, It will resync all read as well as unread message from server. This may also cause the duplication of Communication (emails)." msgstr "Du väljer Synkronisering Alternativ som ALLA. Det kommer att synkronisera alla lästa såväl som olästa meddelanden från server. Detta kan också orsaka kopior av korrespondens (e-post)." -#: public/js/frappe/form/footer/form_timeline.js:413 +#: public/js/frappe/form/footer/form_timeline.js:415 msgctxt "Form timeline" msgid "You attached {0}" msgstr "Du {0}" @@ -28969,9 +29072,9 @@ msgstr "Du kan ändra lagring princip från {0}." msgid "You can continue with the onboarding after exploring this page" msgstr "Du kan fortsätta med Introduktion efter att utforskning av denna sida" -#: core/doctype/user/user.py:543 -msgid "You can disable the user instead of deleting it." -msgstr "Du kan inaktivera användare istället för att ta bort den." +#: model/delete_doc.py:136 +msgid "You can disable this {0} instead of deleting it." +msgstr "Du kan inaktivera denna {0} istället för att radera den." #: core/doctype/file/file.py:691 msgid "You can increase the limit from System Settings." @@ -29063,12 +29166,12 @@ msgstr "Du ändrade värde av {0}" msgid "You changed the values for {0} {1}" msgstr "Du ändrade värde av {0} {1}" -#: public/js/frappe/form/footer/form_timeline.js:442 +#: public/js/frappe/form/footer/form_timeline.js:444 msgctxt "Form timeline" msgid "You changed {0} to {1}" msgstr "Du ändrade {0} till {1}" -#: public/js/frappe/form/footer/form_timeline.js:138 +#: public/js/frappe/form/footer/form_timeline.js:140 #: public/js/frappe/form/sidebar/form_sidebar.js:106 msgid "You created this" msgstr "Du skapade detta" @@ -29098,7 +29201,7 @@ msgstr "Du har inte tillräckligt med recension poäng" msgid "You do not have permission to view this document" msgstr "Du har inte behörighet att se detta dokument" -#: public/js/frappe/form/form.js:955 +#: public/js/frappe/form/form.js:959 msgid "You do not have permissions to cancel all linked documents." msgstr "Du har inte behörighet att annullera alla länkade dokument." @@ -29150,7 +29253,7 @@ msgstr "Du har inte anget någon värde. Fält kommer att vara tom." msgid "You have received a ❤️ like on your blog post" msgstr "Du fick ❤️ gilla på ditt blogg inlägg" -#: twofactor.py:448 +#: twofactor.py:432 msgid "You have to enable Two Factor Auth from System Settings." msgstr "Du behöver ktivera \"\"Two Factor Auth\"\" från System Inställningar." @@ -29170,7 +29273,7 @@ msgstr "Visa {0}" msgid "You haven't added any Dashboard Charts or Number Cards yet." msgstr "Du har inte lagt till några Översiktpanel Diagram eller Nummerkort än." -#: public/js/frappe/list/list_view.js:473 +#: public/js/frappe/list/list_view.js:470 msgid "You haven't created a {0} yet" msgstr "{0} är inte skapad än" @@ -29178,7 +29281,7 @@ msgstr "{0} är inte skapad än" msgid "You hit the rate limit because of too many requests. Please try after sometime." msgstr "Du nådde gräns på grund av för många förfrågningar. Försök igen senare." -#: public/js/frappe/form/footer/form_timeline.js:149 +#: public/js/frappe/form/footer/form_timeline.js:151 #: public/js/frappe/form/sidebar/form_sidebar.js:95 msgid "You last edited this" msgstr "Du ändrade detta för" @@ -29239,7 +29342,7 @@ msgstr "Du måste installera pycups för att använda denna funktion!" msgid "You need to select indexes you want to add first." msgstr "Du måste välja index du vill lägga till först." -#: email/doctype/email_account/email_account.py:147 +#: email/doctype/email_account/email_account.py:153 msgid "You need to set one IMAP folder for {0}" msgstr "Du måste ange en IMAP mapp för {0}" @@ -29251,7 +29354,7 @@ msgstr "Du har inte behörighet för att byta namn" msgid "You need {0} permission to fetch values from {1} {2}" msgstr "Du behöver {0} behörighet för att hämta värden från {1} {2}" -#: public/js/frappe/form/footer/form_timeline.js:418 +#: public/js/frappe/form/footer/form_timeline.js:420 msgctxt "Form timeline" msgid "You removed attachment {0}" msgstr "Du tog bort bilaga {0}" @@ -29278,7 +29381,7 @@ msgstr "Du godkännde detta dokument {0}" msgid "You unfollowed this document" msgstr "Du slutade följa detta dokument" -#: public/js/frappe/form/footer/form_timeline.js:182 +#: public/js/frappe/form/footer/form_timeline.js:184 msgid "You viewed this" msgstr "Du visade detta" @@ -30000,7 +30103,7 @@ msgstr "tagg namn... t.ex. #tagg" msgid "text in document type" msgstr "text i doctype" -#: public/js/frappe/form/controls/data.js:35 +#: public/js/frappe/form/controls/data.js:36 msgid "this form" msgstr "detta formulär" @@ -30045,7 +30148,7 @@ msgstr "via Data Import" msgid "via Google Meet" msgstr "via Google Meet" -#: email/doctype/notification/notification.py:216 +#: email/doctype/notification/notification.py:220 msgid "via Notification" msgstr "via Avisering" @@ -30113,12 +30216,12 @@ msgstr "{0} ${skip_list ? \"\" : type}" msgid "{0} ${type}" msgstr "{0} ${type}" -#: public/js/frappe/data_import/data_exporter.js:79 +#: public/js/frappe/data_import/data_exporter.js:80 #: public/js/frappe/views/gantt/gantt_view.js:54 msgid "{0} ({1})" msgstr "{0} ({1})" -#: public/js/frappe/data_import/data_exporter.js:76 +#: public/js/frappe/data_import/data_exporter.js:77 msgid "{0} ({1}) (1 row mandatory)" msgstr "{0} ({1}) (1 rad erfodras)" @@ -30161,14 +30264,14 @@ msgstr "{0} Google Kalender Händelser synkroniseras." msgid "{0} Google Contacts synced." msgstr "{0} Google Kontakter synkroniseras." -#: public/js/frappe/form/footer/form_timeline.js:463 +#: public/js/frappe/form/footer/form_timeline.js:465 msgid "{0} Liked" msgstr "{0} Gillade" #: public/js/frappe/ui/toolbar/search_utils.js:83 #: public/js/frappe/ui/toolbar/search_utils.js:84 #: public/js/frappe/utils/utils.js:924 -#: public/js/frappe/widgets/chart_widget.js:317 www/list.html:4 www/list.html:8 +#: public/js/frappe/widgets/chart_widget.js:318 www/list.html:4 www/list.html:8 msgid "{0} List" msgstr "{0} Lista" @@ -30195,7 +30298,7 @@ msgstr "{0} Ej Tillåtet att ändra {1} efter godkännande från {2} till {3}" #: public/js/frappe/ui/toolbar/search_utils.js:95 #: public/js/frappe/ui/toolbar/search_utils.js:96 #: public/js/frappe/utils/utils.js:921 -#: public/js/frappe/widgets/chart_widget.js:325 +#: public/js/frappe/widgets/chart_widget.js:326 msgid "{0} Report" msgstr "{0} Rapport" @@ -30214,7 +30317,7 @@ msgstr "{0} Inställningar" msgid "{0} Tree" msgstr "{0} Träd Vy" -#: public/js/frappe/form/footer/form_timeline.js:126 +#: public/js/frappe/form/footer/form_timeline.js:128 #: public/js/frappe/form/sidebar/form_sidebar.js:86 msgid "{0} Web page views" msgstr "{0} Webbsida Visningar" @@ -30228,7 +30331,7 @@ msgstr "{0} Arbetsyta" msgid "{0} added" msgstr "{0} tillagd" -#: public/js/frappe/form/controls/data.js:203 +#: public/js/frappe/form/controls/data.js:204 msgid "{0} already exists. Select another name" msgstr "{0} finns redan. Välj ett annat namn" @@ -30286,7 +30389,7 @@ msgstr "{0} tilldelade dig ny uppgift {1} {2}" msgid "{0} assigned {1}: {2}" msgstr "{0} tilldelad {1}: {2}" -#: public/js/frappe/form/footer/form_timeline.js:414 +#: public/js/frappe/form/footer/form_timeline.js:416 msgctxt "Form timeline" msgid "{0} attached {1}" msgstr "{0} bifogade {1}" @@ -30324,7 +30427,7 @@ msgstr "{0} ändrade värde på {1}" msgid "{0} changed the values for {1} {2}" msgstr "{0} ändrade värdena för {1} {2}" -#: public/js/frappe/form/footer/form_timeline.js:443 +#: public/js/frappe/form/footer/form_timeline.js:445 msgctxt "Form timeline" msgid "{0} changed {1} to {2}" msgstr "{0} ändrade {1} till {2}" @@ -30341,7 +30444,7 @@ msgstr "{0} innehåller ogiltigt Hämta Från uttryck, Hämta från kan inte var msgid "{0} created successfully" msgstr "{0} skapades" -#: public/js/frappe/form/footer/form_timeline.js:139 +#: public/js/frappe/form/footer/form_timeline.js:141 #: public/js/frappe/form/sidebar/form_sidebar.js:107 msgid "{0} created this" msgstr "{0} skapade detta" @@ -30433,7 +30536,7 @@ msgstr "{0} är lagd till E-post Grupp." msgid "{0} has left the conversation in {1} {2}" msgstr "{0} har lämnat konversation i {1} {2}" -#: __init__.py:2493 +#: __init__.py:2499 msgid "{0} has no versions tracked." msgstr "{0} har inga spårade versioner." @@ -30499,7 +30602,7 @@ msgstr "{0} är mindre än {1}" msgid "{0} is like {1}" msgstr "{0} är som {1}" -#: email/doctype/email_account/email_account.py:176 +#: email/doctype/email_account/email_account.py:186 msgid "{0} is mandatory" msgstr "{0} är erfodrad" @@ -30579,7 +30682,7 @@ msgstr "{0} är nu standard utskrift format för {1} DocType" msgid "{0} is one of {1}" msgstr "{0} är en av {1}" -#: email/doctype/email_account/email_account.py:277 model/naming.py:217 +#: email/doctype/email_account/email_account.py:293 model/naming.py:217 #: printing/doctype/print_format/print_format.py:91 utils/csvutils.py:153 msgid "{0} is required" msgstr "{0} erfodras" @@ -30592,15 +30695,15 @@ msgstr "{0} är angiven" msgid "{0} is within {1}" msgstr "{0} är inom {1}" -#: public/js/frappe/list/list_view.js:1601 +#: public/js/frappe/list/list_view.js:1655 msgid "{0} items selected" msgstr "{0} artiklar valda" -#: core/doctype/user/user.py:1328 +#: core/doctype/user/user.py:1343 msgid "{0} just impersonated as you. They gave this reason: {1}" msgstr "{0} efterliknade som du. De gav detta skäl: {1}" -#: public/js/frappe/form/footer/form_timeline.js:150 +#: public/js/frappe/form/footer/form_timeline.js:152 #: public/js/frappe/form/sidebar/form_sidebar.js:96 msgid "{0} last edited this" msgstr "{0} senast redigerade detta" @@ -30663,11 +30766,11 @@ msgstr "{0} Ej Tillåtet att ändra namn på" msgid "{0} not found" msgstr "{0} hittades inte" -#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:992 +#: core/doctype/report/report.py:413 public/js/frappe/list/list_view.js:1029 msgid "{0} of {1}" msgstr "{0} av {1}" -#: public/js/frappe/list/list_view.js:994 +#: public/js/frappe/list/list_view.js:1031 msgid "{0} of {1} ({2} rows with children)" msgstr "{0} av {1} ({2} rader med underordnade)" @@ -30700,11 +30803,11 @@ msgstr "{0} poster sparas i {1} dagar." msgid "{0} records deleted" msgstr "{0} poster raderade" -#: public/js/frappe/data_import/data_exporter.js:228 +#: public/js/frappe/data_import/data_exporter.js:229 msgid "{0} records will be exported" msgstr "{0} poster kommer att exporteras" -#: public/js/frappe/form/footer/form_timeline.js:419 +#: public/js/frappe/form/footer/form_timeline.js:421 msgctxt "Form timeline" msgid "{0} removed attachment {1}" msgstr "{0} tog bort bilaga {1}" @@ -30796,7 +30899,7 @@ msgstr "{0} uppdaterat" msgid "{0} values selected" msgstr "{0} värden valda" -#: public/js/frappe/form/footer/form_timeline.js:183 +#: public/js/frappe/form/footer/form_timeline.js:185 msgid "{0} viewed this" msgstr "{0} visade detta" @@ -30840,7 +30943,7 @@ msgstr "{0} {1} kan inte vara undernod då den har undernoder" msgid "{0} {1} does not exist, select a new target to merge" msgstr "{0} {1} existerar inte. Välj ny mål att sammanfoga" -#: public/js/frappe/form/form.js:946 +#: public/js/frappe/form/form.js:950 msgid "{0} {1} is linked with the following submitted documents: {2}" msgstr "{0} {1} är länkad till följande godkända dokument: {2}" @@ -30848,7 +30951,7 @@ msgstr "{0} {1} är länkad till följande godkända dokument: {2}" msgid "{0} {1} not found" msgstr "{0} {1} hittades inte" -#: model/delete_doc.py:242 +#: model/delete_doc.py:251 msgid "{0} {1}: Submitted Record cannot be deleted. You must {2} Cancel {3} it first." msgstr "{0} {1}: Godkänd Post kan inte raderas. Du måste {2} Annullera {3} det först." @@ -30940,7 +31043,7 @@ msgstr "{0}: Andra behörighet regler kan också gälla" msgid "{0}: Permission at level 0 must be set before higher levels are set" msgstr "{0}: Behörighet på nivå 0 måste anges före högre nivåer anges" -#: public/js/frappe/form/controls/data.js:50 +#: public/js/frappe/form/controls/data.js:51 msgid "{0}: You can increase the limit for the field if required via {1}" msgstr "{0}: Öka gräns för fältet vid behov via {1}" @@ -31024,8 +31127,8 @@ msgstr "{} stöder inte automatisk logg rensning." msgid "{} field cannot be empty." msgstr "{} fält kan inte vara tom." -#: email/doctype/email_account/email_account.py:200 -#: email/doctype/email_account/email_account.py:208 +#: email/doctype/email_account/email_account.py:216 +#: email/doctype/email_account/email_account.py:224 msgid "{} has been disabled. It can only be enabled if {} is checked." msgstr "{} är inaktiverad. Den kan bara aktiveras om {} är markerad." From 67279d14a26196098f1a0b2020375e5b7ceaedb5 Mon Sep 17 00:00:00 2001 From: P-Godfroid <109596710+P-Godfroid@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:43:15 +0200 Subject: [PATCH 125/176] fix: get_token header typo (#27202) Verfication changed into Verification --- frappe/twofactor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/twofactor.py b/frappe/twofactor.py index 9e60bd6a18..9c891c2166 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -349,7 +349,7 @@ def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, mess recipients=user_email, subject=subject or get_email_subject_for_2fa(template_args), message=message or get_email_body_for_2fa(template_args), - header=[_("Verfication Code"), "blue"], + header=[_("Verification Code"), "blue"], delayed=False, retry=3, ) From 968800ce72186b501086c43a6fb806ec6c51654b Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Fri, 26 Jul 2024 18:28:49 +0530 Subject: [PATCH 126/176] fix(babel): not a valid locale identifier (#26749) --- frappe/utils/data.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 3bd8a83ddf..0281efca48 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -717,7 +717,7 @@ def format_date(string_date=None, format_string: str | None = None, parse_day_fi formatted_date = babel.dates.format_date( date, format_string, locale=(frappe.local.lang or "").replace("-", "_") ) - except UnknownLocaleError: + except (UnknownLocaleError, ValueError): format_string = format_string.replace("MM", "%m").replace("dd", "%d").replace("yyyy", "%Y") formatted_date = date.strftime(format_string) return formatted_date @@ -749,7 +749,7 @@ def format_time(time_string=None, format_string: str | None = None) -> str: formatted_time = babel.dates.format_time( time_, format_string, locale=(frappe.local.lang or "").replace("-", "_") ) - except UnknownLocaleError: + except (UnknownLocaleError, ValueError): formatted_time = time_.strftime("%H:%M:%S") return formatted_time @@ -777,7 +777,7 @@ def format_datetime(datetime_string: DateTimeLikeObject, format_string: str | No formatted_datetime = babel.dates.format_datetime( datetime, format_string, locale=(frappe.local.lang or "").replace("-", "_") ) - except UnknownLocaleError: + except (UnknownLocaleError, ValueError): formatted_datetime = datetime.strftime("%Y-%m-%d %H:%M:%S") return formatted_datetime From 76da422081f907ccb745509fb671299aaba7b98c Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sat, 27 Jul 2024 12:25:37 +0530 Subject: [PATCH 127/176] fix(minor): move Create Workspace button to footer --- .../js/frappe/views/workspace/workspace.js | 37 ++++++++++++++----- frappe/public/scss/desk/desktop.scss | 6 +++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index c5f7c112e0..2cf812eae4 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -381,6 +381,16 @@ frappe.views.Workspace = class Workspace { if (!this.body.find("#editorjs")[0]) { this.$page = $(`
    + `).appendTo(this.body); } @@ -456,9 +466,10 @@ frappe.views.Workspace = class Workspace { this.clear_page_actions(); if (current_page.is_editable) { - this.page.set_secondary_action( - __("Edit"), - async () => { + this.body + .find(".btn-edit-workspace") + .removeClass("hide") + .on("click", async () => { if (!this.editor || !this.editor.readOnly) return; this.is_read_only = false; this.toggle_hidden_workspaces(true); @@ -470,15 +481,21 @@ frappe.views.Workspace = class Workspace { this.show_sidebar_actions(); this.make_blocks_sortable(); }); - }, - "es-line-edit" - ); + }); + } else { + this.body.find(".btn-edit-workspace").addClass("hide"); } // need to add option for icons in inner buttons as well - if (this.has_create_access) - this.page.add_inner_button(__("Create Workspace"), () => { - this.initialize_new_page(true); - }); + if (this.has_create_access) { + this.body + .find(".btn-new-workspace") + .removeClass("hide") + .on("click", () => { + this.initialize_new_page(true); + }); + } else { + this.body.find(".btn-new-workspace").addClass("hide"); + } } initialize_editorjs_undo() { diff --git a/frappe/public/scss/desk/desktop.scss b/frappe/public/scss/desk/desktop.scss index 6d24492be0..f7e44536a3 100644 --- a/frappe/public/scss/desk/desktop.scss +++ b/frappe/public/scss/desk/desktop.scss @@ -1015,6 +1015,12 @@ body { padding: var(--padding-sm); } + .workspace-footer { + height: 30px; + display: flex; + flex-direction: row-reverse; + } + .block-menu-item-icon svg { width: 18px; height: 18px; From 40557741b2549543f1df7eae42086e35a5df0ba4 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sun, 28 Jul 2024 11:54:40 +0530 Subject: [PATCH 128/176] fix(tests): [Workspace] Fix tests for actions in footer --- cypress/integration/workspace.js | 10 +++++----- cypress/integration/workspace_blocks.js | 2 +- frappe/public/js/frappe/views/workspace/workspace.js | 12 +++++++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cypress/integration/workspace.js b/cypress/integration/workspace.js index 4079877c9c..0f8e24c82f 100644 --- a/cypress/integration/workspace.js +++ b/cypress/integration/workspace.js @@ -18,7 +18,7 @@ context("Workspace 2.0", () => { }).as("new_page"); cy.get(".codex-editor__redactor .ce-block"); - cy.get('.custom-actions button[data-label="Create%20Workspace"]').click(); + cy.get('.workspace-footer button[data-label="New"]').click(); cy.fill_field("title", "Test Private Page", "Data"); cy.get_open_dialog().find(".modal-header").click(); cy.get_open_dialog().find(".btn-primary").click(); @@ -48,7 +48,7 @@ context("Workspace 2.0", () => { }).as("new_page"); cy.get(".codex-editor__redactor .ce-block"); - cy.get('.custom-actions button[data-label="Create%20Workspace"]').click(); + cy.get('.workspace-footer button[data-label="New"]').click(); cy.fill_field("title", "Test Child Page", "Data"); cy.fill_field("parent", "Test Private Page", "Select"); cy.get_open_dialog().find(".modal-header").click(); @@ -196,7 +196,7 @@ context("Workspace 2.0", () => { }).as("hide_page"); cy.get(".codex-editor__redactor .ce-block"); - cy.get(".standard-actions .btn-secondary[data-label=Edit]").click(); + cy.get(".workspace-footer .btn-secondary[data-label=Edit]").click(); cy.get('.sidebar-item-container[item-name="Duplicate Page"]') .find(".sidebar-item-control .setting-btn") @@ -217,7 +217,7 @@ context("Workspace 2.0", () => { }).as("unhide_page"); cy.get(".codex-editor__redactor .ce-block"); - cy.get(".standard-actions .btn-secondary[data-label=Edit]").click(); + cy.get(".workspace-footer .btn-secondary[data-label=Edit]").click(); cy.get('.sidebar-item-container[item-name="Duplicate Page"]') .find('[title="Unhide Workspace"]') @@ -237,7 +237,7 @@ context("Workspace 2.0", () => { }).as("page_deleted"); cy.get(".codex-editor__redactor .ce-block"); - cy.get(".standard-actions .btn-secondary[data-label=Edit]").click(); + cy.get(".workspace-footer .btn-secondary[data-label=Edit]").click(); cy.get('.sidebar-item-container[item-name="Duplicate Page"]') .find(".sidebar-item-control .setting-btn") diff --git a/cypress/integration/workspace_blocks.js b/cypress/integration/workspace_blocks.js index 8b93c4e50d..480d57eaf8 100644 --- a/cypress/integration/workspace_blocks.js +++ b/cypress/integration/workspace_blocks.js @@ -18,7 +18,7 @@ context("Workspace Blocks", () => { cy.visit("/app/website"); cy.get(".codex-editor__redactor .ce-block"); - cy.get('.custom-actions button[data-label="Create%20Workspace"]').click(); + cy.get('.workspace-footer button[data-label="New"]').click(); cy.fill_field("title", "Test Block Page", "Data"); cy.get_open_dialog().find(".modal-header").click(); cy.get_open_dialog().find(".btn-primary").click(); diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index 2cf812eae4..d5d95def6d 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -382,13 +382,19 @@ frappe.views.Workspace = class Workspace { this.$page = $(`
    `).appendTo(this.body); From f9bfafc134ba99411bb2ca8e408f6f9f1deee36a Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Sun, 28 Jul 2024 13:35:17 +0530 Subject: [PATCH 129/176] fix(Web Form): enable no copy for 'Is Standard' flag (#27222) --- frappe/website/doctype/web_form/web_form.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/website/doctype/web_form/web_form.json b/frappe/website/doctype/web_form/web_form.json index c4eeca4cac..e4e29ad270 100644 --- a/frappe/website/doctype/web_form/web_form.json +++ b/frappe/website/doctype/web_form/web_form.json @@ -94,7 +94,8 @@ "default": "0", "fieldname": "is_standard", "fieldtype": "Check", - "label": "Is Standard" + "label": "Is Standard", + "no_copy": 1 }, { "default": "0", @@ -393,7 +394,7 @@ "icon": "icon-edit", "is_published_field": "published", "links": [], - "modified": "2024-03-23 16:04:01.886581", + "modified": "2024-07-27 20:32:06.331745", "modified_by": "Administrator", "module": "Website", "name": "Web Form", From da3698ba30a88bffbef5e850388cb62f691986aa Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sun, 28 Jul 2024 19:13:54 +0530 Subject: [PATCH 130/176] fix(tests): [Workspace] Fix tests for actions in footer --- cypress/integration/workspace.js | 4 ++-- cypress/integration/workspace_blocks.js | 4 ++-- frappe/public/js/frappe/views/workspace/workspace.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cypress/integration/workspace.js b/cypress/integration/workspace.js index 0f8e24c82f..542cb3ddfc 100644 --- a/cypress/integration/workspace.js +++ b/cypress/integration/workspace.js @@ -18,7 +18,7 @@ context("Workspace 2.0", () => { }).as("new_page"); cy.get(".codex-editor__redactor .ce-block"); - cy.get('.workspace-footer button[data-label="New"]').click(); + cy.get('.workspace-footer button[data-label="New"]:visible').click(); cy.fill_field("title", "Test Private Page", "Data"); cy.get_open_dialog().find(".modal-header").click(); cy.get_open_dialog().find(".btn-primary").click(); @@ -48,7 +48,7 @@ context("Workspace 2.0", () => { }).as("new_page"); cy.get(".codex-editor__redactor .ce-block"); - cy.get('.workspace-footer button[data-label="New"]').click(); + cy.get('.workspace-footer button[data-label="New"]:visible').click(); cy.fill_field("title", "Test Child Page", "Data"); cy.fill_field("parent", "Test Private Page", "Select"); cy.get_open_dialog().find(".modal-header").click(); diff --git a/cypress/integration/workspace_blocks.js b/cypress/integration/workspace_blocks.js index 480d57eaf8..9032ca1523 100644 --- a/cypress/integration/workspace_blocks.js +++ b/cypress/integration/workspace_blocks.js @@ -18,7 +18,7 @@ context("Workspace Blocks", () => { cy.visit("/app/website"); cy.get(".codex-editor__redactor .ce-block"); - cy.get('.workspace-footer button[data-label="New"]').click(); + cy.get('.workspace-footer button[data-label="New"]:visible').click(); cy.fill_field("title", "Test Block Page", "Data"); cy.get_open_dialog().find(".modal-header").click(); cy.get_open_dialog().find(".btn-primary").click(); @@ -159,7 +159,7 @@ context("Workspace Blocks", () => { ]); cy.get(".codex-editor__redactor .ce-block"); - cy.get(".standard-actions .btn-secondary[data-label=Edit]").click(); + cy.get(".workspace-footer .btn[data-label=Edit]").click(); cy.get(".ce-block").first().click({ force: true }).type("{enter}"); cy.get(".block-list-container .block-list-item").contains("Number Card").click(); diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index d5d95def6d..c09b2d65f2 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -388,7 +388,7 @@ frappe.views.Workspace = class Workspace { - + +
    + `).appendTo(this.body); + + this.body.find(".btn-new-workspace").on("click", () => { + this.initialize_new_page(true); + }); + + this.body.find(".btn-edit-workspace").on("click", async () => { + if (!this.editor || !this.editor.readOnly) return; + this.is_read_only = false; + this.toggle_hidden_workspaces(true); + await this.editor.readOnly.toggle(); + this.editor.isReady.then(() => { + this.body.addClass("edit-mode"); + this.initialize_editorjs_undo(); + this.setup_customization_buttons(this._page); + this.show_sidebar_actions(); + this.make_blocks_sortable(); + }); + }); + } + get_pages() { return frappe.xcall("frappe.desk.desktop.get_workspace_sidebar_items"); } @@ -379,25 +420,9 @@ frappe.views.Workspace = class Workspace { async show_page(page) { if (!this.body.find("#editorjs")[0]) { - this.$page = $(` + $(`
    - - `).appendTo(this.body); + `).appendTo(this.body.find(".editor-js-container")); } if (this.all_pages.length) { @@ -406,6 +431,7 @@ frappe.views.Workspace = class Workspace { let pages = page.public && this.public_pages.length ? this.public_pages : this.private_pages; let current_page = pages.filter((p) => p.title == page.name)[0]; + this._page = current_page; this.content = current_page && JSON.parse(current_page.content); this.content && this.add_custom_cards_in_content(); @@ -472,33 +498,13 @@ frappe.views.Workspace = class Workspace { this.clear_page_actions(); if (current_page.is_editable) { - this.body - .find(".btn-edit-workspace") - .removeClass("hide") - .on("click", async () => { - if (!this.editor || !this.editor.readOnly) return; - this.is_read_only = false; - this.toggle_hidden_workspaces(true); - await this.editor.readOnly.toggle(); - this.editor.isReady.then(() => { - this.body.addClass("edit-mode"); - this.initialize_editorjs_undo(); - this.setup_customization_buttons(current_page); - this.show_sidebar_actions(); - this.make_blocks_sortable(); - }); - }); + this.body.find(".btn-edit-workspace").removeClass("hide"); } else { this.body.find(".btn-edit-workspace").addClass("hide"); } // need to add option for icons in inner buttons as well if (this.has_create_access) { - this.body - .find(".btn-new-workspace") - .removeClass("hide") - .on("click", () => { - this.initialize_new_page(true); - }); + this.body.find(".btn-new-workspace").removeClass("hide"); } else { this.body.find(".btn-new-workspace").addClass("hide"); } diff --git a/frappe/public/scss/desk/desktop.scss b/frappe/public/scss/desk/desktop.scss index f7e44536a3..b0c0173088 100644 --- a/frappe/public/scss/desk/desktop.scss +++ b/frappe/public/scss/desk/desktop.scss @@ -994,6 +994,10 @@ body { .links-widget-box { background-color: var(--bg-color) !important; } + + .workspace-footer { + display: none; + } } } From 4a602917a88d34d87399c19ce4335d9a68d693ff Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 29 Jul 2024 22:25:08 +0530 Subject: [PATCH 135/176] fix(test): fix workspace_blocks.js --- cypress/integration/workspace_blocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/workspace_blocks.js b/cypress/integration/workspace_blocks.js index 4874cdbeca..e601efc9b3 100644 --- a/cypress/integration/workspace_blocks.js +++ b/cypress/integration/workspace_blocks.js @@ -174,7 +174,7 @@ context("Workspace Blocks", () => { cy.get("@number_card").find(".widget-title").should("contain", "Test Number Card"); // edit number card - cy.get(".standard-actions .btn-secondary[data-label=Edit]").click(); + cy.get(".btn-edit-workspace").click(); cy.get("@number_card").realHover().find(".widget-control .edit-button").click(); cy.get_field("label", "Data").invoke("val", "ToDo Count"); cy.click_modal_primary_button("Save"); From bf92887259d918c068f66b8c5b1014a555b74607 Mon Sep 17 00:00:00 2001 From: mahsem <137205921+mahsem@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:31:24 +0200 Subject: [PATCH 136/176] fix: translation in form.js (#26907) Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com> --- frappe/public/js/frappe/form/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index bd74ee5bd1..458851e698 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -515,7 +515,7 @@ frappe.ui.form.Form = class FrappeForm { // feedback frappe.msgprint({ - message: __("{} Complete", [action.label]), + message: __("{} Complete", [__(action.label)]), alert: true, }); }); From b0bba0ad31726bccb1533d221d2a67a9a04f15c4 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:44:06 +0200 Subject: [PATCH 137/176] fix: extract translatable strings from .vue files (#27251) --- babel_extractors.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/babel_extractors.csv b/babel_extractors.csv index ff8faafaff..7f2103c4d4 100644 --- a/babel_extractors.csv +++ b/babel_extractors.csv @@ -7,5 +7,6 @@ hooks.py,frappe.gettext.extractors.navbar.extract **.py,frappe.gettext.extractors.python.extract **.js,frappe.gettext.extractors.javascript.extract **.html,frappe.gettext.extractors.html_template.extract +**.vue,frappe.gettext.extractors.html_template.extract **/custom/*.json,frappe.gettext.extractors.customization.extract **/fixtures/custom_field.json,frappe.gettext.extractors.custom_field.extract \ No newline at end of file From f75da85d8394e08e4436bd087baee7481cf9844b Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Tue, 30 Jul 2024 20:14:57 +0200 Subject: [PATCH 138/176] fix: remove context from translatable strings in Workspace (#27249) --- frappe/gettext/extractors/workspace.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frappe/gettext/extractors/workspace.py b/frappe/gettext/extractors/workspace.py index 76ca108df4..4c58c373be 100644 --- a/frappe/gettext/extractors/workspace.py +++ b/frappe/gettext/extractors/workspace.py @@ -29,8 +29,8 @@ def extract(fileobj, *args, **kwargs): yield from ( ( None, - "pgettext", - (link.get("link_to") if link.get("link_type") == "DocType" else None, link.get("label")), + "_", + link.get("label"), [f"Label of a {link.get('type')} in the {workspace_name} Workspace"], ) for link in data.get("links", []) @@ -38,8 +38,8 @@ def extract(fileobj, *args, **kwargs): yield from ( ( None, - "pgettext", - (link.get("link_to") if link.get("link_type") == "DocType" else None, link.get("description")), + "_", + link.get("description"), [f"Description of a {link.get('type')} in the {workspace_name} Workspace"], ) for link in data.get("links", []) @@ -47,8 +47,8 @@ def extract(fileobj, *args, **kwargs): yield from ( ( None, - "pgettext", - (shortcut.get("link_to") if shortcut.get("type") == "DocType" else None, shortcut.get("label")), + "_", + shortcut.get("label"), [f"Label of a shortcut in the {workspace_name} Workspace"], ) for shortcut in data.get("shortcuts", []) @@ -56,8 +56,8 @@ def extract(fileobj, *args, **kwargs): yield from ( ( None, - "pgettext", - (shortcut.get("link_to") if shortcut.get("type") == "DocType" else None, shortcut.get("format")), + "_", + shortcut.get("format"), [f"Count format of shortcut in the {workspace_name} Workspace"], ) for shortcut in data.get("shortcuts", []) From 10e296a77980a0a7c43bb70c028a550146acafdd Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 30 Jul 2024 23:46:30 +0530 Subject: [PATCH 139/176] chore: update POT file (#27253) --- frappe/locale/main.pot | 837 ++++++++++++++++++++++++++++++++--------- 1 file changed, 662 insertions(+), 175 deletions(-) diff --git a/frappe/locale/main.pot b/frappe/locale/main.pot index 1ba70391ab..044b40a645 100644 --- a/frappe/locale/main.pot +++ b/frappe/locale/main.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Frappe Framework VERSION\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-07-21 09:33+0000\n" -"PO-Revision-Date: 2024-07-21 09:33+0000\n" +"POT-Creation-Date: 2024-07-30 18:02+0000\n" +"PO-Revision-Date: 2024-07-30 18:02+0000\n" "Last-Translator: developers@frappe.io\n" "Language-Team: developers@frappe.io\n" "MIME-Version: 1.0\n" @@ -167,6 +167,10 @@ msgstr "" msgid "1 month ago" msgstr "" +#: public/js/print_format_builder/PrintFormat.vue:3 +msgid "1 of 2" +msgstr "" + #: public/js/frappe/data_import/data_exporter.js:227 msgid "1 record will be exported" msgstr "" @@ -979,7 +983,7 @@ msgstr "" #: public/js/frappe/form/grid_row.js:471 #: public/js/frappe/form/sidebar/assign_to.js:100 #: public/js/frappe/form/templates/set_sharing.html:68 -#: public/js/frappe/list/bulk_operations.js:407 +#: public/js/frappe/list/bulk_operations.js:437 #: public/js/frappe/views/dashboard/dashboard_view.js:440 #: public/js/frappe/views/reports/query_report.js:266 #: public/js/frappe/views/reports/query_report.js:294 @@ -1041,6 +1045,7 @@ msgstr "" #: public/js/frappe/views/reports/query_report.js:1684 #: public/js/frappe/views/reports/report_view.js:324 #: public/js/frappe/views/reports/report_view.js:349 +#: public/js/print_format_builder/Field.vue:112 msgid "Add Column" msgstr "" @@ -1131,7 +1136,7 @@ msgstr "" msgid "Add Subscribers" msgstr "" -#: public/js/frappe/list/bulk_operations.js:395 +#: public/js/frappe/list/bulk_operations.js:425 msgid "Add Tags" msgstr "" @@ -1181,6 +1186,7 @@ msgid "Add a comment" msgstr "" #: printing/page/print_format_builder/print_format_builder_layout.html:28 +#: public/js/form_builder/components/Tabs.vue:192 msgid "Add a new section" msgstr "" @@ -1204,10 +1210,42 @@ msgstr "" msgid "Add a {0} Chart" msgstr "" +#: public/js/form_builder/components/Section.vue:271 +#: public/js/print_format_builder/PrintFormatSection.vue:115 +msgid "Add column" +msgstr "" + +#: public/js/form_builder/components/AddFieldButton.vue:9 +#: public/js/form_builder/components/AddFieldButton.vue:48 +msgid "Add field" +msgstr "" + +#: public/js/form_builder/components/Sidebar.vue:49 +#: public/js/form_builder/components/Tabs.vue:153 +msgid "Add new tab" +msgstr "" + +#: public/js/print_format_builder/PrintFormatSection.vue:125 +msgid "Add page break" +msgstr "" + #: custom/doctype/client_script/client_script.js:16 msgid "Add script for Child Table" msgstr "" +#: public/js/print_format_builder/PrintFormatSection.vue:111 +msgid "Add section above" +msgstr "" + +#: public/js/form_builder/components/Section.vue:265 +msgid "Add section below" +msgstr "" + +#: public/js/form_builder/components/Sidebar.vue:52 +#: public/js/form_builder/components/Tabs.vue:157 +msgid "Add tab" +msgstr "" + #: public/js/frappe/utils/dashboard_utils.js:263 #: public/js/frappe/views/reports/query_report.js:252 msgid "Add to Dashboard" @@ -1445,7 +1483,7 @@ msgstr "" msgid "Aggregate Function Based On" msgstr "" -#: desk/doctype/dashboard_chart/dashboard_chart.py:399 +#: desk/doctype/dashboard_chart/dashboard_chart.py:409 msgid "Aggregate Function field is required to create a dashboard chart" msgstr "" @@ -2074,7 +2112,7 @@ msgstr "" msgid "Append To" msgstr "" -#: email/doctype/email_account/email_account.py:195 +#: email/doctype/email_account/email_account.py:196 msgid "Append To can be one of {0}" msgstr "" @@ -2115,6 +2153,10 @@ msgstr "" msgid "Applied On" msgstr "" +#: public/js/form_builder/components/Field.vue:103 +msgid "Apply" +msgstr "" + #: public/js/frappe/list/list_view.js:1942 msgctxt "Button in list view actions menu" msgid "Apply Assignment Rule" @@ -2217,7 +2259,7 @@ msgstr "" msgid "Are you sure you want to delete all rows?" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:899 +#: public/js/frappe/views/workspace/workspace.js:928 msgid "Are you sure you want to delete page {0}?" msgstr "" @@ -2225,6 +2267,21 @@ msgstr "" msgid "Are you sure you want to delete the attachment?" msgstr "" +#: public/js/form_builder/components/Section.vue:197 +msgctxt "Confirmation dialog message" +msgid "Are you sure you want to delete the column? All the fields in the column will be moved to the previous column." +msgstr "" + +#: public/js/form_builder/components/Section.vue:126 +msgctxt "Confirmation dialog message" +msgid "Are you sure you want to delete the section? All the columns along with fields in the section will be moved to the previous section." +msgstr "" + +#: public/js/form_builder/components/Tabs.vue:65 +msgctxt "Confirmation dialog message" +msgid "Are you sure you want to delete the tab? All the sections along with fields in the tab will be moved to the previous tab." +msgstr "" + #: public/js/frappe/web_form/web_form.js:185 msgid "Are you sure you want to discard the changes?" msgstr "" @@ -2462,6 +2519,7 @@ msgstr "" #: core/doctype/docfield/docfield.json #: custom/doctype/custom_field/custom_field.json #: custom/doctype/customize_form_field/customize_form_field.json +#: public/js/form_builder/components/controls/AttachControl.vue:15 #: public/js/frappe/form/controls/attach.js:5 #: website/doctype/web_form_field/web_form_field.json msgid "Attach" @@ -2494,6 +2552,10 @@ msgstr "" msgid "Attach Print" msgstr "" +#: public/js/frappe/file_uploader/WebLink.vue:10 +msgid "Attach a web link" +msgstr "" + #: website/doctype/website_slideshow/website_slideshow.js:8 msgid "Attach files / urls and add in table." msgstr "" @@ -2597,6 +2659,11 @@ msgstr "" msgid "Auth URL Data" msgstr "" +#. Label of the backend_app_flow (Check) field in DocType 'Email Account' +#: email/doctype/email_account/email_account.json +msgid "Authenticate as Service Principal" +msgstr "" + #. Label of the authentication_column (Section Break) field in DocType 'Email #. Account' #. Label of the authentication_credential_section (Section Break) field in @@ -2620,7 +2687,7 @@ msgstr "" msgid "Authentication Error: Reauthorize OAuth for Email Account {0}." msgstr "" -#: email/doctype/email_account/email_account.py:328 +#: email/doctype/email_account/email_account.py:329 msgid "Authentication failed while receiving emails from Email Account: {0}." msgstr "" @@ -2834,11 +2901,11 @@ msgstr "" msgid "Automatic" msgstr "" -#: email/doctype/email_account/email_account.py:766 +#: email/doctype/email_account/email_account.py:767 msgid "Automatic Linking can be activated only for one Email Account." msgstr "" -#: email/doctype/email_account/email_account.py:760 +#: email/doctype/email_account/email_account.py:761 msgid "Automatic Linking can be activated only if Incoming is enabled." msgstr "" @@ -2978,6 +3045,7 @@ msgstr "" msgid "BCC" msgstr "" +#: public/js/frappe/file_uploader/ImageCropper.vue:31 #: public/js/frappe/widgets/onboarding_widget.js:181 msgid "Back" msgstr "" @@ -3032,6 +3100,10 @@ msgstr "" msgid "Background Jobs Queue" msgstr "" +#: public/js/frappe/list/bulk_operations.js:87 +msgid "Background Print (required for >25 documents)" +msgstr "" + #. Label of the background_workers (Section Break) field in DocType 'System #. Settings' #. Label of the background_workers (Table) field in DocType 'System Health @@ -3421,6 +3493,7 @@ msgstr "" #. Option for the 'Position' (Select) field in DocType 'Form Tour Step' #: desk/doctype/form_tour_step/form_tour_step.json +#: public/js/print_format_builder/PrintFormatControls.vue:154 msgid "Bottom" msgstr "" @@ -3428,11 +3501,13 @@ msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: desk/doctype/form_tour_step/form_tour_step.json #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:248 msgid "Bottom Center" msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:247 msgid "Bottom Left" msgstr "" @@ -3440,6 +3515,7 @@ msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: desk/doctype/form_tour_step/form_tour_step.json #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:249 msgid "Bottom Right" msgstr "" @@ -3551,7 +3627,7 @@ msgstr "" msgid "Bulk Delete" msgstr "" -#: public/js/frappe/list/bulk_operations.js:291 +#: public/js/frappe/list/bulk_operations.js:321 msgid "Bulk Edit" msgstr "" @@ -3567,7 +3643,7 @@ msgstr "" msgid "Bulk Operation Successful" msgstr "" -#: public/js/frappe/list/bulk_operations.js:122 +#: public/js/frappe/list/bulk_operations.js:131 msgid "Bulk PDF Export" msgstr "" @@ -3805,6 +3881,7 @@ msgstr "" msgid "Callback Title" msgstr "" +#: public/js/frappe/file_uploader/FileUploader.vue:150 #: public/js/frappe/ui/capture.js:334 msgid "Camera" msgstr "" @@ -3812,7 +3889,7 @@ msgstr "" #. Label of the campaign (Link) field in DocType 'Newsletter' #. Label of the campaign (Data) field in DocType 'Web Page View' #: email/doctype/newsletter/newsletter.json -#: public/js/frappe/utils/utils.js:1723 +#: public/js/frappe/utils/utils.js:1724 #: website/doctype/web_page_view/web_page_view.json #: website/report/website_analytics/website_analytics.js:39 msgid "Campaign" @@ -3963,7 +4040,7 @@ msgstr "" msgid "Cannot cancel before submitting. See Transition {0}" msgstr "" -#: public/js/frappe/list/bulk_operations.js:264 +#: public/js/frappe/list/bulk_operations.js:294 msgid "Cannot cancel {0}." msgstr "" @@ -3991,7 +4068,7 @@ msgstr "" msgid "Cannot create a {0} against a child document: {1}" msgstr "" -#: desk/doctype/workspace/workspace.py:250 +#: desk/doctype/workspace/workspace.py:254 msgid "Cannot create private workspace of other users" msgstr "" @@ -4003,11 +4080,11 @@ msgstr "" msgid "Cannot delete or cancel because {0} {1} is linked with {2} {3} {4}" msgstr "" -#: desk/doctype/workspace/workspace.py:415 +#: desk/doctype/workspace/workspace.py:419 msgid "Cannot delete private workspace of other users" msgstr "" -#: desk/doctype/workspace/workspace.py:408 +#: desk/doctype/workspace/workspace.py:412 msgid "Cannot delete public workspace without Workspace Manager role" msgstr "" @@ -4023,6 +4100,13 @@ msgstr "" msgid "Cannot delete standard field {0}. You can hide it instead." msgstr "" +#: public/js/form_builder/components/Field.vue:38 +#: public/js/form_builder/components/Section.vue:117 +#: public/js/form_builder/components/Section.vue:190 +#: public/js/form_builder/components/Tabs.vue:56 +msgid "Cannot delete standard field. You can hide it if you want" +msgstr "" + #: custom/doctype/customize_form/customize_form.js:347 msgid "Cannot delete standard link. You can hide it if you want" msgstr "" @@ -4031,7 +4115,7 @@ msgstr "" msgid "Cannot delete system generated field {0}. You can hide it instead." msgstr "" -#: public/js/frappe/list/bulk_operations.js:185 +#: public/js/frappe/list/bulk_operations.js:215 msgid "Cannot delete {0}" msgstr "" @@ -4043,11 +4127,11 @@ msgstr "" msgid "Cannot edit Standard Dashboards" msgstr "" -#: email/doctype/notification/notification.py:122 +#: email/doctype/notification/notification.py:183 msgid "Cannot edit Standard Notification. To edit, please disable this and duplicate it" msgstr "" -#: desk/doctype/dashboard_chart/dashboard_chart.py:377 +#: desk/doctype/dashboard_chart/dashboard_chart.py:387 msgid "Cannot edit Standard charts" msgstr "" @@ -4112,7 +4196,7 @@ msgstr "" msgid "Cannot set 'Report' permission if 'Only If Creator' permission is set" msgstr "" -#: email/doctype/notification/notification.py:139 +#: email/doctype/notification/notification.py:200 msgid "Cannot set Notification with event {0} on Document Type {1}" msgstr "" @@ -4120,16 +4204,16 @@ msgstr "" msgid "Cannot share {0} with submit permission as the doctype {1} is not submittable" msgstr "" -#: public/js/frappe/list/bulk_operations.js:261 +#: public/js/frappe/list/bulk_operations.js:291 msgid "Cannot submit {0}." msgstr "" -#: desk/doctype/workspace/workspace.py:349 +#: desk/doctype/workspace/workspace.py:353 msgid "Cannot update private workspace of other users" msgstr "" #: desk/doctype/bulk_update/bulk_update.js:26 -#: public/js/frappe/list/bulk_operations.js:336 +#: public/js/frappe/list/bulk_operations.js:366 msgid "Cannot update {0}" msgstr "" @@ -4141,7 +4225,7 @@ msgstr "" msgid "Cannot use {0} in order/group by" msgstr "" -#: public/js/frappe/list/bulk_operations.js:267 +#: public/js/frappe/list/bulk_operations.js:297 msgid "Cannot {0} {1}." msgstr "" @@ -4228,11 +4312,20 @@ msgctxt "Coins" msgid "Change" msgstr "" +#: public/js/print_format_builder/LetterHeadEditor.vue:38 +msgid "Change Image" +msgstr "" + #. Label of the label (Data) field in DocType 'Customize Form' #: custom/doctype/customize_form/customize_form.json msgid "Change Label (via Custom Translation)" msgstr "" +#: public/js/print_format_builder/LetterHeadEditor.vue:45 +#: public/js/print_format_builder/LetterHeadEditor.vue:141 +msgid "Change Letter Head" +msgstr "" + #. Label of the change_password (Section Break) field in DocType 'User' #: core/doctype/user/user.json msgid "Change Password" @@ -4421,14 +4514,16 @@ msgstr "" msgid "Choose Existing Card or create New Card" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1399 +#: public/js/frappe/views/workspace/workspace.js:1428 msgid "Choose a block or continue typing" msgstr "" +#: public/js/form_builder/components/controls/DataControl.vue:18 #: public/js/frappe/form/controls/color.js:5 msgid "Choose a color" msgstr "" +#: public/js/form_builder/components/controls/DataControl.vue:21 #: public/js/frappe/form/controls/icon.js:5 msgid "Choose an icon" msgstr "" @@ -4516,6 +4611,10 @@ msgstr "" msgid "Click on Authorize Google Drive Access to authorize Google Drive Access." msgstr "" +#: public/js/frappe/file_uploader/FileUploader.vue:499 +msgid "Click on a file to select it." +msgstr "" + #: templates/emails/login_with_email_link.html:19 msgid "Click on the button to log in to {0}" msgstr "" @@ -4536,6 +4635,10 @@ msgstr "" msgid "Click on the link below to verify your request" msgstr "" +#: public/js/frappe/file_uploader/FileUploader.vue:200 +msgid "Click on the lock icon to toggle public/private" +msgstr "" + #: integrations/doctype/google_calendar/google_calendar.py:102 #: integrations/doctype/google_contacts/google_contacts.py:41 #: integrations/doctype/google_drive/google_drive.py:53 @@ -4651,6 +4754,10 @@ msgstr "" msgid "Close Condition" msgstr "" +#: public/js/form_builder/components/FieldProperties.vue:79 +msgid "Close properties" +msgstr "" + #. Option for the 'Status' (Select) field in DocType 'Activity Log' #. Option for the 'Status' (Select) field in DocType 'Communication' #. Option for the 'Status' (Select) field in DocType 'Event' @@ -4771,6 +4878,8 @@ msgstr "" #. Label of the column (Data) field in DocType 'Recorder Suggested Index' #: core/doctype/recorder_suggested_index/recorder_suggested_index.json #: printing/page/print_format_builder/print_format_builder_column_selector.html:7 +#: public/js/form_builder/components/Section.vue:270 +#: public/js/print_format_builder/ConfigureColumns.vue:8 msgid "Column" msgstr "" @@ -5100,6 +5209,10 @@ msgstr "" msgid "Configure Recorder" msgstr "" +#: public/js/print_format_builder/Field.vue:103 +msgid "Configure columns for {0}" +msgstr "" + #. Description of the 'Amended Documents' (Section Break) field in DocType #. 'Document Naming Settings' #: core/doctype/document_naming_settings/document_naming_settings.json @@ -5297,7 +5410,7 @@ msgstr "" #: core/doctype/comment/comment.json desk/doctype/note/note.json #: desk/doctype/workspace/workspace.json #: email/doctype/newsletter/newsletter.json -#: public/js/frappe/utils/utils.js:1738 +#: public/js/frappe/utils/utils.js:1739 #: website/doctype/blog_post/blog_post.json #: website/doctype/help_article/help_article.json #: website/doctype/web_page/web_page.json @@ -5510,7 +5623,7 @@ msgstr "" #: public/js/frappe/views/file/file_view.js:112 #: public/js/frappe/views/interaction.js:18 #: public/js/frappe/views/reports/query_report.js:1188 -#: public/js/frappe/views/workspace/workspace.js:1231 +#: public/js/frappe/views/workspace/workspace.js:1260 #: workflow/page/workflow_builder/workflow_builder.js:46 msgid "Create" msgstr "" @@ -5534,6 +5647,10 @@ msgstr "" msgid "Create Chart" msgstr "" +#: public/js/form_builder/components/controls/TableControl.vue:62 +msgid "Create Child Doctype" +msgstr "" + #. Label of the create_contact (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json msgid "Create Contacts from Incoming Emails" @@ -5544,7 +5661,7 @@ msgstr "" msgid "Create Custom Fields" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:939 +#: public/js/frappe/views/workspace/workspace.js:968 msgid "Create Duplicate" msgstr "" @@ -5553,6 +5670,11 @@ msgstr "" msgid "Create Entry" msgstr "" +#: public/js/print_format_builder/LetterHeadEditor.vue:59 +#: public/js/print_format_builder/LetterHeadEditor.vue:195 +msgid "Create Letter Head" +msgstr "" + #. Label of the create_log (Check) field in DocType 'Scheduled Job Type' #: core/doctype/scheduled_job_type/scheduled_job_type.json msgid "Create Log" @@ -5581,10 +5703,6 @@ msgstr "" msgid "Create User Email" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:479 -msgid "Create Workspace" -msgstr "" - #: printing/page/print_format_builder/print_format_builder_start.html:16 msgid "Create a New Format" msgstr "" @@ -5703,6 +5821,10 @@ msgstr "" msgid "Cron format is required for job types with Cron frequency." msgstr "" +#: public/js/frappe/file_uploader/ImageCropper.vue:34 +msgid "Crop" +msgstr "" + #: public/js/frappe/form/grid_row_form.js:42 msgid "Ctrl + Down" msgstr "" @@ -5915,6 +6037,7 @@ msgstr "" #: printing/page/print_format_builder/print_format_builder.js:190 #: printing/page/print_format_builder/print_format_builder.js:720 +#: public/js/print_format_builder/PrintFormatControls.vue:192 msgid "Custom HTML" msgstr "" @@ -6013,7 +6136,7 @@ msgstr "" msgid "Customization onboarding is all done!" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:525 +#: public/js/frappe/views/workspace/workspace.js:554 msgid "Customizations Discarded" msgstr "" @@ -6517,7 +6640,7 @@ msgstr "" #. Label of the default_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:217 +#: email/doctype/email_account/email_account.py:218 msgid "Default Incoming" msgstr "" @@ -6537,7 +6660,7 @@ msgstr "" #. Label of the default_outgoing (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:225 +#: email/doctype/email_account/email_account.py:226 msgid "Default Outgoing" msgstr "" @@ -6652,7 +6775,7 @@ msgstr "" msgid "Defaults" msgstr "" -#: email/doctype/email_account/email_account.py:236 +#: email/doctype/email_account/email_account.py:237 msgid "Defaults Updated" msgstr "" @@ -6682,7 +6805,7 @@ msgstr "" #: public/js/frappe/form/grid.js:63 public/js/frappe/form/toolbar.js:434 #: public/js/frappe/views/reports/report_view.js:1654 #: public/js/frappe/views/treeview.js:308 -#: public/js/frappe/views/workspace/workspace.js:837 +#: public/js/frappe/views/workspace/workspace.js:866 #: templates/discussions/reply_card.html:35 #: templates/discussions/reply_section.html:29 msgid "Delete" @@ -6701,6 +6824,11 @@ msgstr "" msgid "Delete All" msgstr "" +#: public/js/form_builder/components/Section.vue:196 +msgctxt "Title of confirmation dialog" +msgid "Delete Column" +msgstr "" + #: website/doctype/personal_data_deletion_request/personal_data_deletion_request.js:10 msgid "Delete Data" msgstr "" @@ -6709,7 +6837,17 @@ msgstr "" msgid "Delete Kanban Board" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:838 +#: public/js/form_builder/components/Section.vue:125 +msgctxt "Title of confirmation dialog" +msgid "Delete Section" +msgstr "" + +#: public/js/form_builder/components/Tabs.vue:64 +msgctxt "Title of confirmation dialog" +msgid "Delete Tab" +msgstr "" + +#: public/js/frappe/views/workspace/workspace.js:867 msgid "Delete Workspace" msgstr "" @@ -6717,10 +6855,40 @@ msgstr "" msgid "Delete and Generate New" msgstr "" +#: public/js/form_builder/components/Section.vue:203 +msgctxt "Button text" +msgid "Delete column" +msgstr "" + #: public/js/frappe/form/footer/form_timeline.js:721 msgid "Delete comment?" msgstr "" +#: public/js/form_builder/components/Section.vue:205 +msgctxt "Button text" +msgid "Delete entire column with fields" +msgstr "" + +#: public/js/form_builder/components/Section.vue:134 +msgctxt "Button text" +msgid "Delete entire section with fields" +msgstr "" + +#: public/js/form_builder/components/Tabs.vue:73 +msgctxt "Button text" +msgid "Delete entire tab with fields" +msgstr "" + +#: public/js/form_builder/components/Section.vue:132 +msgctxt "Button text" +msgid "Delete section" +msgstr "" + +#: public/js/form_builder/components/Tabs.vue:71 +msgctxt "Button text" +msgid "Delete tab" +msgstr "" + #: email/doctype/email_unsubscribe/email_unsubscribe.py:29 msgid "Delete this record to allow sending to this email address" msgstr "" @@ -6777,7 +6945,7 @@ msgstr "" msgid "Deleting {0}" msgstr "" -#: public/js/frappe/list/bulk_operations.js:172 +#: public/js/frappe/list/bulk_operations.js:202 msgid "Deleting {0} records..." msgstr "" @@ -6968,6 +7136,7 @@ msgstr "" #: custom/doctype/customize_form/customize_form.json #: desk/doctype/event/event.json #: desk/page/user_profile/user_profile_sidebar.html:45 +#: public/js/form_builder/components/Tabs.vue:92 #: public/js/form_builder/store.js:259 public/js/form_builder/utils.js:38 #: public/js/frappe/form/layout.js:137 public/js/frappe/views/treeview.js:271 msgid "Details" @@ -7117,14 +7286,14 @@ msgstr "" msgid "Disabled" msgstr "" -#: email/doctype/email_account/email_account.js:261 +#: email/doctype/email_account/email_account.js:265 msgid "Disabled Auto Reply" msgstr "" #: public/js/frappe/form/toolbar.js:316 #: public/js/frappe/views/communication.js:30 #: public/js/frappe/views/dashboard/dashboard_view.js:70 -#: public/js/frappe/views/workspace/workspace.js:516 +#: public/js/frappe/views/workspace/workspace.js:545 #: public/js/frappe/web_form/web_form.js:187 msgid "Discard" msgstr "" @@ -7189,6 +7358,10 @@ msgstr "" msgid "Display Depends On (JS)" msgstr "" +#: public/js/print_format_builder/PrintFormatControls.vue:210 +msgid "Divider" +msgstr "" + #. Label of the do_not_create_new_user (Check) field in DocType 'LDAP Settings' #: integrations/doctype/ldap_settings/ldap_settings.json msgid "Do Not Create New User " @@ -7418,7 +7591,7 @@ msgstr "" msgid "Doctype required" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1317 +#: public/js/frappe/views/workspace/workspace.js:1346 msgid "Doctype with same route already exist. Please choose different title." msgstr "" @@ -7432,6 +7605,7 @@ msgstr "" #: core/doctype/audit_trail/audit_trail.json core/doctype/doctype/doctype.json #: core/doctype/permission_inspector/permission_inspector.json #: desk/doctype/notification_subscribed_document/notification_subscribed_document.json +#: public/js/frappe/views/render_preview.js:42 msgid "Document" msgstr "" @@ -7710,7 +7884,7 @@ msgstr "" msgid "Document renaming from {0} to {1} has been queued" msgstr "" -#: desk/doctype/dashboard_chart/dashboard_chart.py:386 +#: desk/doctype/dashboard_chart/dashboard_chart.py:396 msgid "Document type is required to create a dashboard chart" msgstr "" @@ -7815,6 +7989,8 @@ msgstr "" #: public/js/frappe/form/form_tour.js:16 public/js/frappe/ui/messages.js:231 #: public/js/onboarding_tours/onboarding_tours.js:17 +#: public/js/print_format_builder/HTMLEditor.vue:5 +#: public/js/print_format_builder/LetterHeadEditor.vue:52 msgid "Done" msgstr "" @@ -7823,6 +7999,10 @@ msgstr "" msgid "Donut" msgstr "" +#: public/js/form_builder/components/EditableInput.vue:43 +msgid "Double click to edit label" +msgstr "" + #: core/doctype/file/file.js:5 #: email/doctype/auto_email_report/auto_email_report.js:8 #: public/js/frappe/form/grid.js:63 @@ -7851,7 +8031,7 @@ msgstr "" msgid "Download Link" msgstr "" -#: public/js/frappe/list/bulk_operations.js:125 +#: public/js/frappe/list/bulk_operations.js:134 msgid "Download PDF" msgstr "" @@ -7886,15 +8066,35 @@ msgstr "" #: public/js/frappe/views/workspace/blocks/header.js:46 #: public/js/frappe/views/workspace/blocks/paragraph.js:136 #: public/js/frappe/views/workspace/blocks/spacer.js:44 -#: public/js/frappe/views/workspace/workspace.js:579 +#: public/js/frappe/views/workspace/workspace.js:608 #: public/js/frappe/widgets/base_widget.js:33 msgid "Drag" msgstr "" +#: public/js/form_builder/components/Tabs.vue:189 +msgid "Drag & Drop a section here from another tab" +msgstr "" + +#: public/js/frappe/file_uploader/FileUploader.vue:14 +msgid "Drag and drop files here or upload from" +msgstr "" + +#: public/js/print_format_builder/ConfigureColumns.vue:76 +msgid "Drag columns to set order. Column width is set in percentage. The total width should not be more than 100. Columns marked in red will be removed." +msgstr "" + #: printing/page/print_format_builder/print_format_builder_layout.html:3 msgid "Drag elements from the sidebar to add. Drag them back to trash." msgstr "" +#: public/js/workflow_builder/WorkflowBuilder.vue:296 +msgid "Drag to add state" +msgstr "" + +#: public/js/frappe/file_uploader/FileUploader.vue:172 +msgid "Drop files here" +msgstr "" + #. Label of the dropbox_access_token (Password) field in DocType 'Dropbox #. Settings' #: integrations/doctype/dropbox_settings/dropbox_settings.json @@ -7940,8 +8140,8 @@ msgstr "" #: public/js/frappe/form/grid_row_form.js:42 #: public/js/frappe/form/toolbar.js:388 -#: public/js/frappe/views/workspace/workspace.js:822 -#: public/js/frappe/views/workspace/workspace.js:989 +#: public/js/frappe/views/workspace/workspace.js:851 +#: public/js/frappe/views/workspace/workspace.js:1018 msgid "Duplicate" msgstr "" @@ -7957,8 +8157,8 @@ msgstr "" msgid "Duplicate Name" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:561 -#: public/js/frappe/views/workspace/workspace.js:823 +#: public/js/frappe/views/workspace/workspace.js:590 +#: public/js/frappe/views/workspace/workspace.js:852 msgid "Duplicate Workspace" msgstr "" @@ -7966,7 +8166,11 @@ msgstr "" msgid "Duplicate current row" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1004 +#: public/js/form_builder/components/Field.vue:245 +msgid "Duplicate field" +msgstr "" + +#: public/js/frappe/views/workspace/workspace.js:1033 msgid "Duplicate of {0} named as {1} is created successfully" msgstr "" @@ -8059,8 +8263,7 @@ msgstr "" #: public/js/frappe/form/toolbar.js:681 #: public/js/frappe/views/reports/query_report.js:815 #: public/js/frappe/views/reports/query_report.js:1634 -#: public/js/frappe/views/workspace/workspace.js:460 -#: public/js/frappe/views/workspace/workspace.js:816 +#: public/js/frappe/views/workspace/workspace.js:845 #: public/js/frappe/widgets/base_widget.js:64 #: public/js/frappe/widgets/chart_widget.js:299 #: public/js/frappe/widgets/number_card_widget.js:331 @@ -8115,6 +8318,10 @@ msgstr "" msgid "Edit Filters" msgstr "" +#: public/js/print_format_builder/PrintFormat.vue:29 +msgid "Edit Footer" +msgstr "" + #: printing/doctype/print_format/print_format.js:28 msgid "Edit Format" msgstr "" @@ -8124,14 +8331,27 @@ msgid "Edit Full Form" msgstr "" #: printing/page/print_format_builder/print_format_builder_field.html:26 +#: public/js/print_format_builder/Field.vue:83 msgid "Edit HTML" msgstr "" +#: public/js/print_format_builder/PrintFormat.vue:9 +msgid "Edit Header" +msgstr "" + #: printing/page/print_format_builder/print_format_builder.js:602 #: printing/page/print_format_builder/print_format_builder_layout.html:8 msgid "Edit Heading" msgstr "" +#: public/js/print_format_builder/LetterHeadEditor.vue:52 +msgid "Edit Letter Head" +msgstr "" + +#: public/js/print_format_builder/PrintFormat.vue:35 +msgid "Edit Letter Head Footer" +msgstr "" + #: public/js/frappe/widgets/widget_dialog.js:42 msgid "Edit Links" msgstr "" @@ -8181,7 +8401,7 @@ msgstr "" msgid "Edit Values" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:817 +#: public/js/frappe/views/workspace/workspace.js:846 msgid "Edit Workspace" msgstr "" @@ -8189,6 +8409,10 @@ msgstr "" msgid "Edit mode" msgstr "" +#: public/js/form_builder/components/Field.vue:254 +msgid "Edit the {0} Doctype" +msgstr "" + #: printing/page/print_format_builder/print_format_builder.js:713 msgid "Edit to add content" msgstr "" @@ -8296,7 +8520,7 @@ msgctxt "Email Account" msgid "Email Account" msgstr "" -#: email/doctype/email_account/email_account.py:332 +#: email/doctype/email_account/email_account.py:333 msgid "Email Account Disabled." msgstr "" @@ -8540,6 +8764,10 @@ msgstr "" msgid "Embed code copied" msgstr "" +#: public/js/form_builder/components/Section.vue:285 +msgid "Empty column" +msgstr "" + #. Label of the enable (Check) field in DocType 'Google Calendar' #. Label of the enable (Check) field in DocType 'Google Contacts' #. Label of the enable (Check) field in DocType 'Google Drive' @@ -8601,7 +8829,7 @@ msgstr "" #. Label of the enable_incoming (Check) field in DocType 'Email Account' #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:218 +#: email/doctype/email_account/email_account.py:219 msgid "Enable Incoming" msgstr "" @@ -8614,7 +8842,7 @@ msgstr "" #. Label of the enable_outgoing (Check) field in DocType 'Email Account' #: core/doctype/user_email/user_email.json #: email/doctype/email_account/email_account.json -#: email/doctype/email_account/email_account.py:226 +#: email/doctype/email_account/email_account.py:227 msgid "Enable Outgoing" msgstr "" @@ -8755,7 +8983,7 @@ msgstr "" msgid "Enabled Scheduler" msgstr "" -#: email/doctype/email_account/email_account.py:987 +#: email/doctype/email_account/email_account.py:995 msgid "Enabled email inbox for user {0}" msgstr "" @@ -8768,7 +8996,7 @@ msgstr "" msgid "Enables Calendar and Gantt views." msgstr "" -#: email/doctype/email_account/email_account.js:256 +#: email/doctype/email_account/email_account.js:260 msgid "Enabling auto reply on an incoming email account will send automated replies to all the synchronized emails. Do you wish to continue?" msgstr "" @@ -9040,9 +9268,9 @@ msgstr "" msgid "Error in Header/Footer Script" msgstr "" -#: email/doctype/notification/notification.py:443 -#: email/doctype/notification/notification.py:559 -#: email/doctype/notification/notification.py:565 +#: email/doctype/notification/notification.py:504 +#: email/doctype/notification/notification.py:620 +#: email/doctype/notification/notification.py:626 msgid "Error in Notification" msgstr "" @@ -9050,11 +9278,11 @@ msgstr "" msgid "Error in print format on line {0}: {1}" msgstr "" -#: email/doctype/email_account/email_account.py:664 +#: email/doctype/email_account/email_account.py:665 msgid "Error while connecting to email account {0}" msgstr "" -#: email/doctype/notification/notification.py:556 +#: email/doctype/notification/notification.py:617 msgid "Error while evaluating Notification {0}. Please fix your template." msgstr "" @@ -9491,6 +9719,7 @@ msgstr "" msgid "Failed to enable scheduler: {0}" msgstr "" +#: email/doctype/notification/notification.py:103 #: integrations/doctype/webhook/webhook.py:139 msgid "Failed to evaluate conditions: {}" msgstr "" @@ -9523,6 +9752,14 @@ msgstr "" msgid "Failed to optimize image: {0}" msgstr "" +#: email/doctype/notification/notification.py:120 +msgid "Failed to render message: {}" +msgstr "" + +#: email/doctype/notification/notification.py:138 +msgid "Failed to render subject: {}" +msgstr "" + #: email/doctype/email_queue/email_queue.py:294 msgid "Failed to send email with subject:" msgstr "" @@ -9587,6 +9824,8 @@ msgstr "" #: core/doctype/docfield/docfield.json #: custom/doctype/custom_field/custom_field.json #: custom/doctype/customize_form_field/customize_form_field.json +#: public/js/form_builder/components/controls/FetchFromControl.vue:29 +#: public/js/form_builder/components/controls/FetchFromControl.vue:34 msgid "Fetch From" msgstr "" @@ -9625,7 +9864,7 @@ msgstr "" #: desk/doctype/number_card/number_card.json #: desk/doctype/onboarding_step/onboarding_step.json #: desk/page/leaderboard/leaderboard.js:131 -#: public/js/frappe/list/bulk_operations.js:297 +#: public/js/frappe/list/bulk_operations.js:327 #: public/js/frappe/list/list_view_permission_restrictions.html:3 #: public/js/frappe/views/reports/query_report.js:236 #: public/js/frappe/views/reports/query_report.js:1723 @@ -9662,6 +9901,15 @@ msgstr "" msgid "Field Name" msgstr "" +#: public/js/print_format_builder/PrintFormatSection.vue:141 +msgid "Field Orientation (Left-Right)" +msgstr "" + +#: public/js/print_format_builder/PrintFormatSection.vue:148 +msgid "Field Orientation (Top-Down)" +msgstr "" + +#: public/js/print_format_builder/PrintFormatControls.vue:233 #: public/js/print_format_builder/utils.js:69 msgid "Field Template" msgstr "" @@ -9707,7 +9955,7 @@ msgstr "" msgid "Field {0} not found." msgstr "" -#: email/doctype/notification/notification.py:348 +#: email/doctype/notification/notification.py:409 msgid "Field {0} on document {1} is neither a Mobile number field nor a Customer or User link" msgstr "" @@ -9785,6 +10033,7 @@ msgstr "" #: desk/doctype/list_view_settings/list_view_settings.json #: public/js/frappe/list/list_settings.js:132 #: public/js/frappe/views/kanban/kanban_settings.js:111 +#: public/js/print_format_builder/PrintFormatControls.vue:83 #: website/doctype/personal_data_deletion_step/personal_data_deletion_step.json #: website/doctype/web_template/web_template.json msgid "Fields" @@ -9843,6 +10092,10 @@ msgctxt "File" msgid "File" msgstr "" +#: public/js/frappe/file_uploader/FileUploader.vue:459 +msgid "File \"{0}\" was skipped because of invalid file type" +msgstr "" + #: core/doctype/file/utils.py:128 msgid "File '{0}' not found" msgstr "" @@ -9940,7 +10193,7 @@ msgstr "" #: desk/doctype/number_card/number_card.js:205 #: desk/doctype/number_card/number_card.js:336 #: email/doctype/auto_email_report/auto_email_report.js:90 -#: public/js/frappe/list/base_list.js:890 +#: public/js/frappe/list/base_list.js:887 #: public/js/frappe/ui/filters/filter_list.js:134 #: website/doctype/web_form/web_form.js:197 msgid "Filter" @@ -10120,6 +10373,10 @@ msgstr "" msgid "First set the name and save the record." msgstr "" +#: public/js/workflow_builder/WorkflowBuilder.vue:304 +msgid "Fit" +msgstr "" + #. Label of the flag (Data) field in DocType 'Language' #: core/doctype/language/language.json msgid "Flag" @@ -10237,6 +10494,7 @@ msgstr "" #. Label of the font_size (Data) field in DocType 'Website Theme' #: printing/doctype/print_format/print_format.json #: printing/doctype/print_settings/print_settings.json +#: public/js/print_format_builder/PrintFormatControls.vue:45 #: website/doctype/website_theme/website_theme.json msgid "Font Size" msgstr "" @@ -10574,7 +10832,7 @@ msgstr "" msgid "Frappe Mail" msgstr "" -#: email/doctype/email_account/email_account.py:538 +#: email/doctype/email_account/email_account.py:539 msgid "Frappe Mail OAuth Error" msgstr "" @@ -10593,6 +10851,11 @@ msgstr "" msgid "Frappe page builder using components" msgstr "" +#: public/js/frappe/file_uploader/ImageCropper.vue:112 +msgctxt "Image Cropper" +msgid "Free" +msgstr "" + #. Label of the frequency (Select) field in DocType 'Auto Repeat' #. Label of the frequency (Select) field in DocType 'Scheduled Job Type' #. Label of the document_follow_frequency (Select) field in DocType 'User' @@ -10769,12 +11032,12 @@ msgstr "" msgid "Generate New Report" msgstr "" -#: public/js/frappe/ui/toolbar/awesome_bar.js:368 +#: public/js/frappe/ui/toolbar/awesome_bar.js:391 msgid "Generate Random Password" msgstr "" #: public/js/frappe/ui/toolbar/toolbar.js:172 -#: public/js/frappe/utils/utils.js:1772 +#: public/js/frappe/utils/utils.js:1773 msgid "Generate Tracking URL" msgstr "" @@ -10787,7 +11050,7 @@ msgstr "" msgid "Geolocation" msgstr "" -#: email/doctype/notification/notification.js:193 +#: email/doctype/notification/notification.js:205 msgid "Get Alerts for Today" msgstr "" @@ -11057,6 +11320,7 @@ msgstr "" #. Label of the google_drive_section (Section Break) field in DocType 'Google #. Drive' #: integrations/doctype/google_drive/google_drive.json +#: public/js/frappe/file_uploader/FileUploader.vue:164 msgid "Google Drive" msgstr "" @@ -11097,6 +11361,7 @@ msgstr "" #. Label of the font (Data) field in DocType 'Print Format' #. Label of the google_font (Data) field in DocType 'Website Theme' #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:28 #: website/doctype/website_theme/website_theme.json msgid "Google Font" msgstr "" @@ -11159,6 +11424,10 @@ msgstr "" msgid "Green" msgstr "" +#: public/js/form_builder/components/controls/TableControl.vue:53 +msgid "Grid Empty State" +msgstr "" + #: public/js/frappe/ui/keyboard.js:126 msgid "Grid Shortcuts" msgstr "" @@ -11188,7 +11457,7 @@ msgstr "" msgid "Group By Type" msgstr "" -#: desk/doctype/dashboard_chart/dashboard_chart.py:397 +#: desk/doctype/dashboard_chart/dashboard_chart.py:407 msgid "Group By field is required to create a dashboard chart" msgstr "" @@ -11250,6 +11519,7 @@ msgstr "" #: printing/doctype/letter_head/letter_head.json #: printing/doctype/print_format/print_format.json #: printing/doctype/print_format/print_format.py:91 +#: public/js/print_format_builder/Field.vue:86 #: website/doctype/blog_post/blog_post.json #: website/doctype/web_form_field/web_form_field.json #: website/doctype/web_page/web_page.js:92 @@ -11474,7 +11744,7 @@ msgstr "" msgid "Helvetica Neue" msgstr "" -#: public/js/frappe/utils/utils.js:1769 +#: public/js/frappe/utils/utils.js:1770 msgid "Here's your tracking URL" msgstr "" @@ -11512,9 +11782,10 @@ msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: printing/doctype/print_format/print_format.json -#: public/js/frappe/views/workspace/workspace.js:828 +#: public/js/frappe/views/workspace/workspace.js:857 #: public/js/frappe/widgets/base_widget.js:46 #: public/js/frappe/widgets/base_widget.js:178 +#: public/js/print_format_builder/PrintFormatControls.vue:243 #: templates/includes/login/login.js:82 msgid "Hide" msgstr "" @@ -11620,7 +11891,7 @@ msgstr "" msgid "Hide Weekends" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:829 +#: public/js/frappe/views/workspace/workspace.js:858 msgid "Hide Workspace" msgstr "" @@ -11665,6 +11936,7 @@ msgid "Hint: Include symbols, numbers and capital letters in the password" msgstr "" #. Label of the home_tab (Tab Break) field in DocType 'Website Settings' +#: public/js/frappe/file_uploader/FileBrowser.vue:38 #: public/js/frappe/views/file/file_view.js:67 #: public/js/frappe/views/file/file_view.js:88 #: public/js/frappe/views/pageview.js:153 templates/doc.html:19 @@ -11747,6 +12019,10 @@ msgctxt "Label of name column in report" msgid "ID" msgstr "" +#: public/js/print_format_builder/PrintFormatControls.vue:199 +msgid "ID (name)" +msgstr "" + #. Description of the 'Field Name' (Data) field in DocType 'Property Setter' #: custom/doctype/property_setter/property_setter.json msgid "ID (name) of the entity whose property is to be set" @@ -11797,9 +12073,9 @@ msgstr "" #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: integrations/doctype/social_login_key/social_login_key.json -#: public/js/frappe/views/workspace/workspace.js:646 -#: public/js/frappe/views/workspace/workspace.js:974 -#: public/js/frappe/views/workspace/workspace.js:1219 +#: public/js/frappe/views/workspace/workspace.js:675 +#: public/js/frappe/views/workspace/workspace.js:1003 +#: public/js/frappe/views/workspace/workspace.js:1248 #: workflow/doctype/workflow_state/workflow_state.json msgid "Icon" msgstr "" @@ -12536,9 +12812,9 @@ msgstr "" msgid "Indicator Color" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:653 -#: public/js/frappe/views/workspace/workspace.js:981 -#: public/js/frappe/views/workspace/workspace.js:1225 +#: public/js/frappe/views/workspace/workspace.js:682 +#: public/js/frappe/views/workspace/workspace.js:1010 +#: public/js/frappe/views/workspace/workspace.js:1254 msgid "Indicator color" msgstr "" @@ -12870,7 +13146,7 @@ msgstr "" msgid "Invalid Override" msgstr "" -#: integrations/doctype/connected_app/connected_app.py:167 +#: integrations/doctype/connected_app/connected_app.py:191 msgid "Invalid Parameters." msgstr "" @@ -12900,8 +13176,10 @@ msgstr "" msgid "Invalid Transition" msgstr "" -#: core/doctype/file/file.py:218 public/js/frappe/widgets/widget_dialog.js:604 -#: utils/csvutils.py:223 utils/csvutils.py:244 +#: core/doctype/file/file.py:218 +#: public/js/frappe/file_uploader/FileUploader.vue:511 +#: public/js/frappe/widgets/widget_dialog.js:604 utils/csvutils.py:223 +#: utils/csvutils.py:244 msgid "Invalid URL" msgstr "" @@ -12950,7 +13228,7 @@ msgid "Invalid filter: {0}" msgstr "" #: desk/doctype/dashboard/dashboard.py:67 -#: desk/doctype/dashboard_chart/dashboard_chart.py:413 +#: desk/doctype/dashboard_chart/dashboard_chart.py:423 msgid "Invalid json added in the custom options: {0}" msgstr "" @@ -12974,7 +13252,7 @@ msgstr "" msgid "Invalid request arguments" msgstr "" -#: integrations/doctype/connected_app/connected_app.py:173 +#: integrations/doctype/connected_app/connected_app.py:197 msgid "Invalid state." msgstr "" @@ -13651,12 +13929,14 @@ msgstr "" #: desk/doctype/workspace_quick_list/workspace_quick_list.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: printing/page/print_format_builder/print_format_builder.js:474 +#: public/js/form_builder/components/Field.vue:208 #: public/js/frappe/widgets/widget_dialog.js:187 #: public/js/frappe/widgets/widget_dialog.js:255 #: public/js/frappe/widgets/widget_dialog.js:304 #: public/js/frappe/widgets/widget_dialog.js:421 #: public/js/frappe/widgets/widget_dialog.js:645 #: public/js/frappe/widgets/widget_dialog.js:678 +#: public/js/print_format_builder/Field.vue:18 #: templates/form_grid/fields.html:37 #: website/doctype/top_bar_item/top_bar_item.json #: website/doctype/web_template_field/web_template_field.json @@ -13885,7 +14165,7 @@ msgid "Leave blank to repeat always" msgstr "" #: core/doctype/communication/mixins.py:207 -#: email/doctype/email_account/email_account.py:714 +#: email/doctype/email_account/email_account.py:715 msgid "Leave this conversation" msgstr "" @@ -13904,6 +14184,7 @@ msgid "Left" msgstr "" #: printing/page/print_format_builder/print_format_builder.js:483 +#: public/js/print_format_builder/PrintFormatControls.vue:155 msgctxt "alignment" msgid "Left" msgstr "" @@ -13988,7 +14269,8 @@ msgstr "" #: printing/doctype/letter_head/letter_head.json #: printing/page/print/print.js:127 public/js/frappe/form/print_utils.js:18 #: public/js/frappe/form/templates/print_layout.html:16 -#: public/js/frappe/list/bulk_operations.js:51 +#: public/js/frappe/list/bulk_operations.js:52 +#: public/js/print_format_builder/LetterHeadEditor.vue:144 msgid "Letter Head" msgstr "" @@ -14005,6 +14287,7 @@ msgstr "" #. Label of the letter_head_name (Data) field in DocType 'Letter Head' #: printing/doctype/letter_head/letter_head.json +#: public/js/print_format_builder/LetterHeadEditor.vue:198 msgid "Letter Head Name" msgstr "" @@ -14043,6 +14326,10 @@ msgstr "" msgid "Level Name" msgstr "" +#: public/js/frappe/file_uploader/FileUploader.vue:94 +msgid "Library" +msgstr "" + #. Label of the license (Markdown Editor) field in DocType 'Package' #: core/doctype/package/package.json www/attribution.html:36 msgid "License" @@ -14145,6 +14432,7 @@ msgstr "" #: desk/doctype/desktop_icon/desktop_icon.json #: desk/doctype/notification_log/notification_log.json #: desk/doctype/workspace_link/workspace_link.json +#: public/js/frappe/file_uploader/FileUploader.vue:128 #: website/doctype/web_form_field/web_form_field.json #: website/doctype/web_template_field/web_template_field.json msgid "Link" @@ -14386,10 +14674,14 @@ msgctxt "Form timeline" msgid "Load More Communications" msgstr "" +#: public/js/frappe/file_uploader/TreeNode.vue:45 +msgid "Load more" +msgstr "" + #: core/page/permission_manager/permission_manager.js:165 #: public/js/frappe/form/controls/multicheck.js:13 #: public/js/frappe/form/linked_with.js:13 -#: public/js/frappe/list/base_list.js:498 +#: public/js/frappe/list/base_list.js:495 #: public/js/frappe/list/list_view.js:332 public/js/frappe/ui/listing.html:16 #: public/js/frappe/views/reports/query_report.js:1017 msgid "Loading" @@ -14411,6 +14703,7 @@ msgstr "" msgid "Loading versions..." msgstr "" +#: public/js/frappe/file_uploader/TreeNode.vue:45 #: public/js/frappe/form/sidebar/share.js:51 #: public/js/frappe/list/list_sidebar.js:218 #: public/js/frappe/list/list_sidebar_group_by.js:125 @@ -14501,7 +14794,7 @@ msgstr "" msgid "Login Failed please try again" msgstr "" -#: email/doctype/email_account/email_account.py:140 +#: email/doctype/email_account/email_account.py:141 msgid "Login Id is required" msgstr "" @@ -14989,7 +15282,7 @@ msgstr "" #. Option for the 'Priority' (Select) field in DocType 'ToDo' #. Label of the medium (Data) field in DocType 'Web Page View' #: desk/doctype/todo/todo.json public/js/frappe/form/sidebar/assign_to.js:220 -#: public/js/frappe/utils/utils.js:1731 +#: public/js/frappe/utils/utils.js:1732 #: website/doctype/web_page_view/web_page_view.json #: website/report/website_analytics/website_analytics.js:40 msgid "Medium" @@ -15002,6 +15295,7 @@ msgid "Meeting" msgstr "" #. Label of the meets_condition (Data) field in DocType 'Webhook' +#: email/doctype/notification/notification.py:79 #: integrations/doctype/webhook/webhook.json msgid "Meets Condition?" msgstr "" @@ -15065,6 +15359,7 @@ msgstr "" #: email/doctype/email_queue/email_queue.json #: email/doctype/newsletter/newsletter.json #: email/doctype/notification/notification.json +#: email/doctype/notification/notification.py:81 #: public/js/frappe/ui/messages.js:175 #: public/js/frappe/views/communication.js:114 #: workflow/doctype/workflow_document_state/workflow_document_state.json @@ -15113,7 +15408,7 @@ msgstr "" msgid "Message clipped" msgstr "" -#: email/doctype/email_account/email_account.py:333 +#: email/doctype/email_account/email_account.py:334 msgid "Message from server: {0}" msgstr "" @@ -15556,6 +15851,10 @@ msgstr "" msgid "Move To Trash" msgstr "" +#: public/js/form_builder/components/Section.vue:295 +msgid "Move current and all subsequent sections to a new tab" +msgstr "" + #: public/js/frappe/form/form.js:176 msgid "Move cursor to above row" msgstr "" @@ -15572,6 +15871,14 @@ msgstr "" msgid "Move cursor to previous column" msgstr "" +#: public/js/form_builder/components/Section.vue:294 +msgid "Move sections to new tab" +msgstr "" + +#: public/js/form_builder/components/Field.vue:237 +msgid "Move the current field and the following fields to a new column" +msgstr "" + #: public/js/frappe/form/grid_row.js:165 msgid "Move to Row Number" msgstr "" @@ -15635,6 +15942,10 @@ msgstr "" msgid "My Account" msgstr "" +#: public/js/frappe/file_uploader/FileUploader.vue:57 +msgid "My Device" +msgstr "" + #. Label of a standard navbar item #. Type: Route #: hooks.py @@ -15811,11 +16122,11 @@ msgstr "" msgid "Navigation Settings" msgstr "" -#: desk/doctype/workspace/workspace.py:301 +#: desk/doctype/workspace/workspace.py:305 msgid "Need Workspace Manager role to edit private workspace of other users" msgstr "" -#: desk/doctype/workspace/workspace.py:345 +#: desk/doctype/workspace/workspace.py:349 msgid "Need Workspace Manager role to hide/unhide public workspaces" msgstr "" @@ -15975,7 +16286,7 @@ msgstr "" msgid "New Workflow Name" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1186 +#: public/js/frappe/views/workspace/workspace.js:1215 msgid "New Workspace" msgstr "" @@ -16164,6 +16475,7 @@ msgstr "" #. Settings' #. Option for the 'Standard' (Select) field in DocType 'Print Format' #: core/doctype/page/page.json core/doctype/report/report.json +#: email/doctype/notification/notification.py:100 #: integrations/doctype/ldap_settings/ldap_settings.json #: integrations/doctype/webhook/webhook.py:140 #: printing/doctype/print_format/print_format.json @@ -16200,6 +16512,7 @@ msgstr "" #: core/doctype/data_export/exporter.py:162 #: email/doctype/auto_email_report/auto_email_report.py:288 +#: public/js/form_builder/components/controls/TableControl.vue:64 #: public/js/frappe/data_import/import_preview.js:142 #: public/js/frappe/form/grid.js:63 #: public/js/frappe/form/multi_select_dialog.js:225 @@ -16254,13 +16567,20 @@ msgstr "" msgid "No LDAP User found for email: {0}" msgstr "" +#: public/js/form_builder/components/EditableInput.vue:11 +#: public/js/form_builder/components/EditableInput.vue:14 +#: public/js/form_builder/components/Field.vue:209 +#: public/js/form_builder/components/controls/FetchFromControl.vue:55 +#: public/js/print_format_builder/Field.vue:24 +#: public/js/workflow_builder/components/ActionNode.vue:53 +#: public/js/workflow_builder/components/StateNode.vue:47 #: public/js/workflow_builder/store.js:51 msgid "No Label" msgstr "" #: printing/page/print/print.js:700 printing/page/print/print.js:782 -#: public/js/frappe/list/bulk_operations.js:90 -#: public/js/frappe/list/bulk_operations.js:140 utils/weasyprint.py:52 +#: public/js/frappe/list/bulk_operations.js:98 +#: public/js/frappe/list/bulk_operations.js:170 utils/weasyprint.py:52 msgid "No Letterhead" msgstr "" @@ -16340,7 +16660,7 @@ msgstr "" msgid "No address added yet." msgstr "" -#: email/doctype/notification/notification.js:203 +#: email/doctype/notification/notification.js:215 msgid "No alerts for today" msgstr "" @@ -16360,7 +16680,7 @@ msgstr "" msgid "No changes made because old and new name are the same." msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1491 +#: public/js/frappe/views/workspace/workspace.js:1520 msgid "No changes made on the page" msgstr "" @@ -16500,6 +16820,10 @@ msgstr "" msgid "No records will be exported" msgstr "" +#: email/doctype/notification/notification.py:133 +msgid "No subject" +msgstr "" + #: www/printview.py:442 msgid "No template found at path: {0}" msgstr "" @@ -16681,7 +17005,7 @@ msgstr "" msgid "Not allowed for {0}: {1}" msgstr "" -#: email/doctype/notification/notification.py:440 +#: email/doctype/notification/notification.py:501 msgid "Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings" msgstr "" @@ -16863,15 +17187,15 @@ msgstr "" msgid "Notification sent to" msgstr "" -#: email/doctype/notification/notification.py:345 +#: email/doctype/notification/notification.py:406 msgid "Notification: customer {0} has no Mobile number set" msgstr "" -#: email/doctype/notification/notification.py:331 +#: email/doctype/notification/notification.py:392 msgid "Notification: document {0} has no {1} number set (field: {2})" msgstr "" -#: email/doctype/notification/notification.py:340 +#: email/doctype/notification/notification.py:401 msgid "Notification: user {0} has no Mobile number set" msgstr "" @@ -17079,7 +17403,7 @@ msgstr "" msgid "OAuth Scope" msgstr "" -#: email/doctype/email_account/email_account.js:211 +#: email/doctype/email_account/email_account.js:215 msgid "OAuth has been enabled but not authorised. Please use \"Authorise API Access\" button to do the same." msgstr "" @@ -17092,6 +17416,10 @@ msgstr "" msgid "OPTIONS" msgstr "" +#: public/js/form_builder/components/Tabs.vue:190 +msgid "OR" +msgstr "" + #. Option for the 'Two Factor Authentication method' (Select) field in DocType #. 'System Settings' #: core/doctype/system_settings/system_settings.json @@ -17271,7 +17599,7 @@ msgstr "" msgid "One of" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1326 +#: public/js/frappe/views/workspace/workspace.js:1355 msgid "One of the child page with name {0} already exist in {1} Section. Please update the name of the child page first before moving" msgstr "" @@ -17313,7 +17641,7 @@ msgstr "" msgid "Only Workspace Manager can edit public workspaces" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:550 +#: public/js/frappe/views/workspace/workspace.js:579 msgid "Only Workspace Manager can sort or edit this page" msgstr "" @@ -17443,6 +17771,10 @@ msgstr "" msgid "Open a module or tool" msgstr "" +#: public/js/print_format_builder/Preview.vue:17 +msgid "Open in a new tab" +msgstr "" + #: public/js/frappe/list/list_view.js:1251 msgctxt "Description of a list view shortcut" msgid "Open list item" @@ -17495,6 +17827,7 @@ msgstr "" #: core/doctype/file/file.js:24 #: core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.js:8 +#: public/js/frappe/file_uploader/FilePreview.vue:27 msgid "Optimize" msgstr "" @@ -17809,6 +18142,7 @@ msgid "Page" msgstr "" #. Option for the 'Fieldtype' (Select) field in DocType 'Web Form Field' +#: public/js/print_format_builder/PrintFormatSection.vue:63 #: website/doctype/web_form_field/web_form_field.json msgid "Page Break" msgstr "" @@ -17829,10 +18163,14 @@ msgstr "" msgid "Page HTML" msgstr "" -#: public/js/frappe/list/bulk_operations.js:72 +#: public/js/frappe/list/bulk_operations.js:73 msgid "Page Height (in mm)" msgstr "" +#: public/js/print_format_builder/PrintFormatControls.vue:5 +msgid "Page Margins" +msgstr "" + #. Label of the page_name (Data) field in DocType 'Page' #: core/doctype/page/page.json msgid "Page Name" @@ -17840,6 +18178,7 @@ msgstr "" #. Label of the page_number (Select) field in DocType 'Print Format' #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:63 msgid "Page Number" msgstr "" @@ -17848,7 +18187,7 @@ msgstr "" msgid "Page Route" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1513 +#: public/js/frappe/views/workspace/workspace.js:1542 msgid "Page Saved Successfully" msgstr "" @@ -17862,7 +18201,7 @@ msgstr "" msgid "Page Shortcuts" msgstr "" -#: public/js/frappe/list/bulk_operations.js:65 +#: public/js/frappe/list/bulk_operations.js:66 msgid "Page Size" msgstr "" @@ -17871,7 +18210,7 @@ msgstr "" msgid "Page Title" msgstr "" -#: public/js/frappe/list/bulk_operations.js:79 +#: public/js/frappe/list/bulk_operations.js:80 msgid "Page Width (in mm)" msgstr "" @@ -17880,7 +18219,7 @@ msgid "Page has expired!" msgstr "" #: printing/doctype/print_settings/print_settings.py:70 -#: public/js/frappe/list/bulk_operations.js:98 +#: public/js/frappe/list/bulk_operations.js:106 msgid "Page height and width cannot be zero" msgstr "" @@ -17893,7 +18232,7 @@ msgstr "" msgid "Page to show on the website\n" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1313 +#: public/js/frappe/views/workspace/workspace.js:1342 msgid "Page with title {0} already exist." msgstr "" @@ -17910,9 +18249,9 @@ msgid "Parameter" msgstr "" #: public/js/frappe/model/model.js:142 -#: public/js/frappe/views/workspace/workspace.js:620 -#: public/js/frappe/views/workspace/workspace.js:948 -#: public/js/frappe/views/workspace/workspace.js:1195 +#: public/js/frappe/views/workspace/workspace.js:649 +#: public/js/frappe/views/workspace/workspace.js:977 +#: public/js/frappe/views/workspace/workspace.js:1224 msgid "Parent" msgstr "" @@ -17970,7 +18309,7 @@ msgstr "" msgid "Parent Table" msgstr "" -#: desk/doctype/dashboard_chart/dashboard_chart.py:393 +#: desk/doctype/dashboard_chart/dashboard_chart.py:403 msgid "Parent document type is required to create a dashboard chart" msgstr "" @@ -18062,7 +18401,7 @@ msgstr "" msgid "Password for Base DN" msgstr "" -#: email/doctype/email_account/email_account.py:182 +#: email/doctype/email_account/email_account.py:183 msgid "Password is required or select Awaiting Password" msgstr "" @@ -18419,7 +18758,7 @@ msgstr "" msgid "Plant" msgstr "" -#: email/doctype/email_account/email_account.py:535 +#: email/doctype/email_account/email_account.py:536 msgid "Please Authorize OAuth for Email Account {0}" msgstr "" @@ -18546,7 +18885,8 @@ msgstr "" #: desk/doctype/notification_log/notification_log.js:45 #: email/doctype/auto_email_report/auto_email_report.js:17 #: printing/page/print/print.js:635 printing/page/print/print.js:665 -#: public/js/frappe/utils/utils.js:1426 +#: public/js/frappe/list/bulk_operations.js:161 +#: public/js/frappe/utils/utils.js:1427 msgid "Please enable pop-ups" msgstr "" @@ -18687,6 +19027,10 @@ msgstr "" msgid "Please select a country code for field {1}." msgstr "" +#: public/js/frappe/file_uploader/FileUploader.vue:487 +msgid "Please select a file first." +msgstr "" + #: utils/file_manager.py:50 msgid "Please select a file or url" msgstr "" @@ -18765,7 +19109,7 @@ msgstr "" msgid "Please setup a message first" msgstr "" -#: email/doctype/email_account/email_account.py:423 +#: email/doctype/email_account/email_account.py:424 msgid "Please setup default Email Account from Settings > Email Account" msgstr "" @@ -18781,11 +19125,11 @@ msgstr "" msgid "Please specify a valid parent DocType for {0}" msgstr "" -#: email/doctype/notification/notification.py:88 +#: email/doctype/notification/notification.py:149 msgid "Please specify which date field must be checked" msgstr "" -#: email/doctype/notification/notification.py:91 +#: email/doctype/notification/notification.py:152 msgid "Please specify which value field must be checked" msgstr "" @@ -19011,6 +19355,7 @@ msgstr "" #: desk/doctype/custom_html_block/custom_html_block.json #: email/doctype/newsletter/newsletter.js:14 #: email/doctype/newsletter/newsletter.js:42 +#: email/doctype/notification/notification.js:184 #: integrations/doctype/webhook/webhook.json #: printing/doctype/print_style/print_style.json #: public/js/frappe/form/controls/markdown_editor.js:17 @@ -19046,6 +19391,14 @@ msgstr "" msgid "Preview of generated names" msgstr "" +#: public/js/frappe/views/render_preview.js:19 +msgid "Preview on" +msgstr "" + +#: public/js/print_format_builder/Preview.vue:103 +msgid "Preview type" +msgstr "" + #: email/doctype/email_group/email_group.js:90 msgid "Preview:" msgstr "" @@ -19120,7 +19473,7 @@ msgstr "" #: printing/page/print/print.js:65 public/js/frappe/form/success_action.js:81 #: public/js/frappe/form/templates/print_layout.html:46 #: public/js/frappe/form/toolbar.js:332 public/js/frappe/form/toolbar.js:344 -#: public/js/frappe/list/bulk_operations.js:87 +#: public/js/frappe/list/bulk_operations.js:95 #: public/js/frappe/views/reports/query_report.js:1640 #: public/js/frappe/views/reports/report_view.js:1460 #: public/js/frappe/views/treeview.js:469 www/printview.html:18 @@ -19132,7 +19485,7 @@ msgctxt "Button in list view actions menu" msgid "Print" msgstr "" -#: public/js/frappe/list/bulk_operations.js:47 +#: public/js/frappe/list/bulk_operations.js:48 msgid "Print Documents" msgstr "" @@ -19144,7 +19497,7 @@ msgstr "" #: email/doctype/notification/notification.json #: printing/doctype/print_format/print_format.json #: printing/page/print/print.js:94 printing/page/print/print.js:819 -#: public/js/frappe/list/bulk_operations.js:58 +#: public/js/frappe/list/bulk_operations.js:59 #: website/doctype/web_form/web_form.json msgid "Print Format" msgstr "" @@ -19360,6 +19713,7 @@ msgstr "" #: desk/doctype/custom_html_block/custom_html_block.json #: desk/doctype/event/event.json desk/doctype/kanban_board/kanban_board.json #: desk/doctype/note/note_list.js:8 +#: public/js/frappe/file_uploader/FilePreview.vue:34 msgid "Private" msgstr "" @@ -19462,9 +19816,9 @@ msgstr "" #: desk/doctype/event/event.json desk/doctype/note/note.json #: desk/doctype/note/note_list.js:6 desk/doctype/workspace/workspace.json #: public/js/frappe/views/interaction.js:78 -#: public/js/frappe/views/workspace/workspace.js:627 -#: public/js/frappe/views/workspace/workspace.js:955 -#: public/js/frappe/views/workspace/workspace.js:1201 +#: public/js/frappe/views/workspace/workspace.js:656 +#: public/js/frappe/views/workspace/workspace.js:984 +#: public/js/frappe/views/workspace/workspace.js:1230 msgid "Public" msgstr "" @@ -19870,7 +20224,7 @@ msgstr "" msgid "Re-Run in Console" msgstr "" -#: email/doctype/email_account/email_account.py:720 +#: email/doctype/email_account/email_account.py:721 msgid "Re:" msgstr "" @@ -20191,6 +20545,7 @@ msgstr "" #. Label of the reference_doctype (Link) field in DocType 'Discussion Topic' #: core/doctype/communication/communication.js:143 #: core/report/transaction_log_report/transaction_log_report.py:88 +#: public/js/frappe/views/render_preview.js:34 #: website/doctype/discussion_topic/discussion_topic.json msgid "Reference Doctype" msgstr "" @@ -20345,6 +20700,7 @@ msgstr "" #: public/js/frappe/views/treeview.js:475 #: public/js/frappe/widgets/chart_widget.js:291 #: public/js/frappe/widgets/number_card_widget.js:324 +#: public/js/print_format_builder/Preview.vue:24 msgid "Refresh" msgstr "" @@ -20505,10 +20861,37 @@ msgstr "" msgid "Remove all customizations?" msgstr "" +#: public/js/form_builder/components/Section.vue:286 +msgid "Remove all fields in the column" +msgstr "" + +#: public/js/form_builder/components/Section.vue:278 #: public/js/frappe/utils/datatable.js:9 +#: public/js/print_format_builder/PrintFormatSection.vue:120 msgid "Remove column" msgstr "" +#: public/js/form_builder/components/Field.vue:260 +msgid "Remove field" +msgstr "" + +#: public/js/form_builder/components/Section.vue:279 +msgid "Remove last column" +msgstr "" + +#: public/js/print_format_builder/PrintFormatSection.vue:130 +msgid "Remove page break" +msgstr "" + +#: public/js/form_builder/components/Section.vue:266 +#: public/js/print_format_builder/PrintFormatSection.vue:135 +msgid "Remove section" +msgstr "" + +#: public/js/form_builder/components/Tabs.vue:140 +msgid "Remove tab" +msgstr "" + #: core/doctype/file/file.py:156 msgid "Removed {0}" msgstr "" @@ -20533,6 +20916,10 @@ msgstr "" msgid "Renamed files and replaced code in controllers, please check!" msgstr "" +#: public/js/print_format_builder/PrintFormatSection.vue:17 +msgid "Render labels to the left and values to the right in this section" +msgstr "" + #: core/doctype/communication/communication.js:43 desk/doctype/todo/todo.js:36 msgid "Reopen" msgstr "" @@ -20716,6 +21103,11 @@ msgstr "" msgid "Report Name, Report Field and Fucntion are required to create a number card" msgstr "" +#. Label of the report_ref_doctype (Link) field in DocType 'Workspace Link' +#: desk/doctype/workspace_link/workspace_link.json +msgid "Report Ref DocType" +msgstr "" + #. Label of the report_reference_doctype (Data) field in DocType 'Onboarding #. Step' #: desk/doctype/onboarding_step/onboarding_step.json @@ -20973,6 +21365,10 @@ msgstr "" msgid "Reset Permissions for {0}?" msgstr "" +#: public/js/form_builder/components/Field.vue:114 +msgid "Reset To Default" +msgstr "" + #: public/js/frappe/utils/datatable.js:8 msgid "Reset sorting" msgstr "" @@ -21070,8 +21466,8 @@ msgctxt "Title of message showing restrictions in list view" msgid "Restrictions" msgstr "" -#: public/js/frappe/ui/toolbar/awesome_bar.js:356 -#: public/js/frappe/ui/toolbar/awesome_bar.js:371 +#: public/js/frappe/ui/toolbar/awesome_bar.js:379 +#: public/js/frappe/ui/toolbar/awesome_bar.js:394 msgid "Result" msgstr "" @@ -21179,6 +21575,7 @@ msgid "Right" msgstr "" #: printing/page/print_format_builder/print_format_builder.js:484 +#: public/js/print_format_builder/PrintFormatControls.vue:156 msgctxt "alignment" msgid "Right" msgstr "" @@ -21604,7 +22001,7 @@ msgstr "" msgid "SMS was not sent. Please contact Administrator." msgstr "" -#: email/doctype/email_account/email_account.py:205 +#: email/doctype/email_account/email_account.py:206 msgid "SMTP Server is required" msgstr "" @@ -21714,7 +22111,7 @@ msgstr "" #: public/js/frappe/views/kanban/kanban_view.js:343 #: public/js/frappe/views/reports/query_report.js:1802 #: public/js/frappe/views/reports/report_view.js:1640 -#: public/js/frappe/views/workspace/workspace.js:501 +#: public/js/frappe/views/workspace/workspace.js:530 #: public/js/frappe/widgets/base_widget.js:142 #: public/js/frappe/widgets/quick_list_widget.js:119 #: public/js/print_format_builder/print_format_builder.bundle.js:15 @@ -21769,7 +22166,7 @@ msgstr "" #: public/js/frappe/list/list_settings.js:40 #: public/js/frappe/views/kanban/kanban_settings.js:47 -#: public/js/frappe/views/workspace/workspace.js:513 +#: public/js/frappe/views/workspace/workspace.js:542 msgid "Saving" msgstr "" @@ -22019,14 +22416,30 @@ msgstr "" msgid "Search Priorities" msgstr "" +#: public/js/frappe/file_uploader/FileBrowser.vue:132 +msgid "Search Results" +msgstr "" + #: www/search.py:14 msgid "Search Results for" msgstr "" +#: public/js/frappe/file_uploader/FileBrowser.vue:13 +msgid "Search by filename or extension" +msgstr "" + #: core/doctype/doctype/doctype.py:1436 msgid "Search field {0} is not valid" msgstr "" +#: public/js/print_format_builder/PrintFormatControls.vue:87 +msgid "Search fields" +msgstr "" + +#: public/js/form_builder/components/AddFieldButton.vue:19 +msgid "Search fieldtypes..." +msgstr "" + #: public/js/frappe/ui/toolbar/search.js:50 #: public/js/frappe/ui/toolbar/search.js:69 msgid "Search for anything" @@ -22045,6 +22458,10 @@ msgstr "" msgid "Search or type a command ({0})" msgstr "" +#: public/js/form_builder/components/SearchBox.vue:8 +msgid "Search properties..." +msgstr "" + #: templates/includes/search_box.html:8 msgid "Search results for" msgstr "" @@ -22060,6 +22477,7 @@ msgid "Searching ..." msgstr "" #. Option for the 'Type' (Select) field in DocType 'Web Template' +#: public/js/form_builder/components/Section.vue:263 #: website/doctype/web_template/web_template.json msgid "Section" msgstr "" @@ -22086,6 +22504,16 @@ msgstr "" msgid "Section ID" msgstr "" +#: public/js/form_builder/components/Section.vue:28 +#: public/js/print_format_builder/PrintFormatSection.vue:8 +msgid "Section Title" +msgstr "" + +#: public/js/form_builder/components/Section.vue:217 +#: public/js/form_builder/components/Section.vue:240 +msgid "Section must have at least one column" +msgstr "" + #. Label of the sb3 (Section Break) field in DocType 'User' #: core/doctype/user/user.json msgid "Security Settings" @@ -22204,6 +22632,7 @@ msgid "Select Date Range" msgstr "" #. Label of the doc_type (Link) field in DocType 'Web Form' +#: public/js/form_builder/components/controls/FetchFromControl.vue:28 #: public/js/frappe/doctype/index.js:171 website/doctype/web_form/web_form.json msgid "Select DocType" msgstr "" @@ -22231,6 +22660,7 @@ msgstr "" msgid "Select Document Types to set which User Permissions are used to limit access." msgstr "" +#: public/js/form_builder/components/controls/FetchFromControl.vue:33 #: public/js/frappe/doctype/index.js:200 public/js/frappe/form/toolbar.js:771 msgid "Select Field" msgstr "" @@ -22353,6 +22783,10 @@ msgstr "" msgid "Select a document to preview request data" msgstr "" +#: public/js/form_builder/components/Sidebar.vue:56 +msgid "Select a field to edit its properties." +msgstr "" + #: public/js/frappe/views/treeview.js:337 msgid "Select a group node first." msgstr "" @@ -22379,7 +22813,7 @@ msgstr "" msgid "Select an image of approx width 150px with a transparent background for best results." msgstr "" -#: public/js/frappe/list/bulk_operations.js:35 +#: public/js/frappe/list/bulk_operations.js:36 msgid "Select atleast 1 record for printing" msgstr "" @@ -22402,11 +22836,11 @@ msgstr "" msgid "Select or drag across time slots to create a new event." msgstr "" -#: public/js/frappe/list/bulk_operations.js:209 +#: public/js/frappe/list/bulk_operations.js:239 msgid "Select records for assignment" msgstr "" -#: public/js/frappe/list/bulk_operations.js:230 +#: public/js/frappe/list/bulk_operations.js:260 msgid "Select records for removing assignment" msgstr "" @@ -22423,6 +22857,7 @@ msgstr "" #: public/js/frappe/form/multi_select_dialog.js:81 #: public/js/frappe/form/multi_select_dialog.js:281 #: public/js/frappe/list/list_view_select.js:153 +#: public/js/print_format_builder/Preview.vue:90 msgid "Select {0}" msgstr "" @@ -22870,6 +23305,7 @@ msgstr "" #: desk/doctype/dashboard_chart/dashboard_chart.js:381 #: desk/doctype/number_card/number_card.js:280 +#: public/js/form_builder/components/Field.vue:80 #: website/doctype/web_form/web_form.js:269 msgid "Set Filters" msgstr "" @@ -23044,7 +23480,7 @@ msgstr "" #: integrations/workspace/integrations/integrations.json #: public/js/frappe/form/templates/print_layout.html:25 #: public/js/frappe/ui/toolbar/toolbar.js:289 -#: public/js/frappe/views/workspace/workspace.js:529 +#: public/js/frappe/views/workspace/workspace.js:558 #: website/doctype/web_form/web_form.json #: website/doctype/web_page/web_page.json msgid "Settings" @@ -23815,7 +24251,7 @@ msgstr "" #. Label of the source (Data) field in DocType 'Web Page View' #. Label of the source (Small Text) field in DocType 'Website Route Redirect' -#: public/js/frappe/ui/toolbar/about.js:8 public/js/frappe/utils/utils.js:1715 +#: public/js/frappe/ui/toolbar/about.js:8 public/js/frappe/utils/utils.js:1716 #: website/doctype/web_page_view/web_page_view.json #: website/doctype/website_route_redirect/website_route_redirect.json #: website/report/website_analytics/website_analytics.js:38 @@ -23834,6 +24270,7 @@ msgid "Source Text" msgstr "" #: public/js/frappe/views/workspace/blocks/spacer.js:23 +#: public/js/print_format_builder/PrintFormatControls.vue:204 msgid "Spacer" msgstr "" @@ -23865,6 +24302,11 @@ msgstr "" msgid "Sr" msgstr "" +#: public/js/print_format_builder/Field.vue:143 +#: public/js/print_format_builder/Field.vue:164 +msgid "Sr No." +msgstr "" + #. Label of the stack_html (HTML) field in DocType 'Recorder Query' #: core/doctype/recorder/recorder.js:82 #: core/doctype/recorder_query/recorder_query.json @@ -24034,6 +24476,10 @@ msgstr "" msgid "State" msgstr "" +#: public/js/workflow_builder/components/Properties.vue:24 +msgid "State Properties" +msgstr "" + #. Label of the state (Data) field in DocType 'Address' #: contacts/doctype/address/address.json msgid "State/Province" @@ -24260,6 +24706,7 @@ msgstr "" #: email/doctype/email_template/email_template.json #: email/doctype/newsletter/newsletter.json #: email/doctype/notification/notification.json +#: email/doctype/notification/notification.py:80 #: public/js/frappe/views/communication.js:107 #: public/js/frappe/views/inbox/inbox_view.js:63 msgid "Subject" @@ -24866,6 +25313,10 @@ msgstr "" msgid "Tab Break" msgstr "" +#: public/js/form_builder/components/Tabs.vue:135 +msgid "Tab Label" +msgstr "" + #. Option for the 'Type' (Select) field in DocType 'DocField' #. Label of the table (Data) field in DocType 'Recorder Suggested Index' #. Option for the 'Field Type' (Select) field in DocType 'Custom Field' @@ -24942,7 +25393,7 @@ msgid "Tag Link" msgstr "" #: model/meta.py:52 public/js/frappe/form/templates/form_sidebar.html:100 -#: public/js/frappe/list/bulk_operations.js:400 +#: public/js/frappe/list/bulk_operations.js:430 #: public/js/frappe/list/list_sidebar.html:50 #: public/js/frappe/list/list_sidebar.js:228 public/js/frappe/model/meta.js:204 #: public/js/frappe/model/model.js:133 @@ -25140,7 +25591,7 @@ msgid "" "
    " msgstr "" -#: email/doctype/notification/notification.py:131 +#: email/doctype/notification/notification.py:192 msgid "The Condition '{0}' is invalid" msgstr "" @@ -25830,7 +26281,7 @@ msgstr "" msgid "Time in seconds to retain QR code image on server. Min:240" msgstr "" -#: desk/doctype/dashboard_chart/dashboard_chart.py:402 +#: desk/doctype/dashboard_chart/dashboard_chart.py:412 msgid "Time series based on is required to create a dashboard chart" msgstr "" @@ -25944,9 +26395,9 @@ msgstr "" #: desk/doctype/system_health_report_errors/system_health_report_errors.json #: desk/doctype/workspace/workspace.json #: email/doctype/email_group/email_group.json -#: public/js/frappe/views/workspace/workspace.js:613 -#: public/js/frappe/views/workspace/workspace.js:942 -#: public/js/frappe/views/workspace/workspace.js:1189 +#: public/js/frappe/views/workspace/workspace.js:642 +#: public/js/frappe/views/workspace/workspace.js:971 +#: public/js/frappe/views/workspace/workspace.js:1218 #: website/doctype/blog_category/blog_category.json #: website/doctype/blog_post/blog_post.json #: website/doctype/blog_settings/blog_settings.json @@ -26212,6 +26663,7 @@ msgstr "" #. Option for the 'Position' (Select) field in DocType 'Form Tour Step' #: desk/doctype/form_tour_step/form_tour_step.json +#: public/js/print_format_builder/PrintFormatControls.vue:153 msgid "Top" msgstr "" @@ -26229,6 +26681,7 @@ msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: desk/doctype/form_tour_step/form_tour_step.json #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:245 msgid "Top Center" msgstr "" @@ -26239,6 +26692,7 @@ msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:244 msgid "Top Left" msgstr "" @@ -26254,6 +26708,7 @@ msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: desk/doctype/form_tour_step/form_tour_step.json #: printing/doctype/print_format/print_format.json +#: public/js/print_format_builder/PrintFormatControls.vue:246 msgid "Top Right" msgstr "" @@ -26326,6 +26781,10 @@ msgstr "" msgid "Total number of emails to sync in initial sync process " msgstr "" +#: public/js/print_format_builder/ConfigureColumns.vue:12 +msgid "Total:" +msgstr "" + #: public/js/frappe/views/reports/report_view.js:1178 msgid "Totals" msgstr "" @@ -26392,7 +26851,7 @@ msgstr "" msgid "Track milestones for any document" msgstr "" -#: public/js/frappe/utils/utils.js:1766 +#: public/js/frappe/utils/utils.js:1767 msgid "Tracking URL generated and copied to clipboard" msgstr "" @@ -26412,6 +26871,10 @@ msgstr "" msgid "Transaction Log Report" msgstr "" +#: public/js/workflow_builder/components/Properties.vue:19 +msgid "Transition Properties" +msgstr "" + #. Label of the transition_rules (Section Break) field in DocType 'Workflow' #: workflow/doctype/workflow/workflow.json msgid "Transition Rules" @@ -26757,7 +27220,7 @@ msgstr "" msgid "Unhandled Emails" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:570 +#: public/js/frappe/views/workspace/workspace.js:599 msgid "Unhide Workspace" msgstr "" @@ -26879,7 +27342,7 @@ msgstr "" #: printing/page/print_format_builder/print_format_builder.js:670 #: printing/page/print_format_builder/print_format_builder.js:757 #: public/js/frappe/form/grid_row.js:404 -#: public/js/frappe/views/workspace/workspace.js:661 +#: public/js/frappe/views/workspace/workspace.js:690 msgid "Update" msgstr "" @@ -26889,7 +27352,7 @@ msgstr "" msgid "Update Amendment Naming" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:610 +#: public/js/frappe/views/workspace/workspace.js:639 msgid "Update Details" msgstr "" @@ -26945,7 +27408,7 @@ msgstr "" msgid "Update from Frappe Cloud" msgstr "" -#: public/js/frappe/list/bulk_operations.js:345 +#: public/js/frappe/list/bulk_operations.js:375 msgid "Update {0} records" msgstr "" @@ -26966,7 +27429,7 @@ msgstr "" msgid "Updated To A New Version 🎉" msgstr "" -#: public/js/frappe/list/bulk_operations.js:342 +#: public/js/frappe/list/bulk_operations.js:372 msgid "Updated successfully" msgstr "" @@ -27019,6 +27482,18 @@ msgstr "" msgid "Upload" msgstr "" +#: public/js/print_format_builder/LetterHeadEditor.vue:93 +msgid "Upload Image" +msgstr "" + +#: public/js/frappe/file_uploader/FileUploader.vue:193 +msgid "Upload file" +msgstr "" + +#: public/js/frappe/file_uploader/FileUploader.vue:196 +msgid "Upload {0} files" +msgstr "" + #. Label of the uploaded_to_dropbox (Check) field in DocType 'File' #: core/doctype/file/file.json msgid "Uploaded To Dropbox" @@ -27485,7 +27960,7 @@ msgstr "" msgid "User {0} does not have doctype access via role permission for document {1}" msgstr "" -#: desk/doctype/workspace/workspace.py:253 +#: desk/doctype/workspace/workspace.py:257 msgid "User {0} does not have the permission to create a Workspace." msgstr "" @@ -27630,8 +28105,8 @@ msgstr "" #: email/doctype/auto_email_report/auto_email_report.js:92 #: integrations/doctype/query_parameters/query_parameters.json #: integrations/doctype/webhook_header/webhook_header.json -#: public/js/frappe/list/bulk_operations.js:306 -#: public/js/frappe/list/bulk_operations.js:368 +#: public/js/frappe/list/bulk_operations.js:336 +#: public/js/frappe/list/bulk_operations.js:398 #: public/js/frappe/list/list_view_permission_restrictions.html:4 #: website/doctype/web_form/web_form.js:197 #: website/doctype/website_meta_tag/website_meta_tag.json @@ -27730,7 +28205,7 @@ msgid "Verdana" msgstr "" #: twofactor.py:352 -msgid "Verfication Code" +msgid "Verification Code" msgstr "" #: templates/emails/delete_data_confirmation.html:10 @@ -28024,7 +28499,7 @@ msgstr "" msgid "Web Page Block" msgstr "" -#: public/js/frappe/utils/utils.js:1707 +#: public/js/frappe/utils/utils.js:1708 msgid "Web Page URL" msgstr "" @@ -28417,6 +28892,7 @@ msgstr "" #: custom/doctype/customize_form_field/customize_form_field.json #: desk/doctype/dashboard_chart_link/dashboard_chart_link.json #: printing/page/print_format_builder/print_format_builder_column_selector.html:8 +#: public/js/print_format_builder/ConfigureColumns.vue:11 msgid "Width" msgstr "" @@ -28543,6 +29019,10 @@ msgstr "" msgid "Workflow Data" msgstr "" +#: public/js/workflow_builder/components/Properties.vue:42 +msgid "Workflow Details" +msgstr "" + #. Name of a DocType #: workflow/doctype/workflow_document_state/workflow_document_state.json msgid "Workflow Document State" @@ -28650,19 +29130,19 @@ msgstr "" msgid "Workspace Shortcut" msgstr "" -#: desk/doctype/workspace/workspace.py:285 +#: desk/doctype/workspace/workspace.py:289 msgid "Workspace not found" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1279 +#: public/js/frappe/views/workspace/workspace.js:1308 msgid "Workspace {0} Created Successfully" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:908 +#: public/js/frappe/views/workspace/workspace.js:937 msgid "Workspace {0} Deleted Successfully" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:686 +#: public/js/frappe/views/workspace/workspace.js:715 msgid "Workspace {0} Edited Successfully" msgstr "" @@ -28765,6 +29245,8 @@ msgstr "" #. Settings' #. Option for the 'Standard' (Select) field in DocType 'Print Format' #: core/doctype/page/page.json core/doctype/report/report.json +#: email/doctype/notification/notification.py:94 +#: email/doctype/notification/notification.py:100 #: integrations/doctype/ldap_settings/ldap_settings.json #: integrations/doctype/webhook/webhook.py:130 #: integrations/doctype/webhook/webhook.py:140 @@ -28868,7 +29350,7 @@ msgstr "" msgid "You are only allowed to update order, do not remove or add apps." msgstr "" -#: email/doctype/email_account/email_account.js:245 +#: email/doctype/email_account/email_account.js:249 msgid "You are selecting Sync Option as ALL, It will resync all read as well as unread message from server. This may also cause the duplication of Communication (emails)." msgstr "" @@ -28925,7 +29407,7 @@ msgstr "" msgid "You can only insert images in Markdown fields" msgstr "" -#: public/js/frappe/list/bulk_operations.js:41 +#: public/js/frappe/list/bulk_operations.js:42 msgid "You can only print upto {0} documents at a time" msgstr "" @@ -28975,7 +29457,7 @@ msgctxt "Form timeline" msgid "You cancelled this document {1}" msgstr "" -#: desk/doctype/dashboard_chart/dashboard_chart.py:406 +#: desk/doctype/dashboard_chart/dashboard_chart.py:416 msgid "You cannot create a dashboard chart from single DocTypes" msgstr "" @@ -29082,7 +29564,7 @@ msgstr "" msgid "You have hit the row size limit on database table: {0}" msgstr "" -#: public/js/frappe/list/bulk_operations.js:382 +#: public/js/frappe/list/bulk_operations.js:412 msgid "You have not entered a value. The field will be set to empty." msgstr "" @@ -29179,7 +29661,7 @@ msgstr "" msgid "You need to select indexes you want to add first." msgstr "" -#: email/doctype/email_account/email_account.py:153 +#: email/doctype/email_account/email_account.py:154 msgid "You need to set one IMAP folder for {0}" msgstr "" @@ -29200,7 +29682,7 @@ msgstr "" msgid "You seem good to go!" msgstr "" -#: public/js/frappe/list/bulk_operations.js:30 +#: public/js/frappe/list/bulk_operations.js:31 msgid "You selected Draft or Cancelled documents" msgstr "" @@ -29238,7 +29720,7 @@ msgstr "" msgid "Your Name" msgstr "" -#: public/js/frappe/list/bulk_operations.js:123 +#: public/js/frappe/list/bulk_operations.js:132 msgid "Your PDF is ready for download" msgstr "" @@ -29985,7 +30467,7 @@ msgstr "" msgid "via Google Meet" msgstr "" -#: email/doctype/notification/notification.py:220 +#: email/doctype/notification/notification.py:281 msgid "via Notification" msgstr "" @@ -30066,8 +30548,8 @@ msgstr "" msgid "{0} ({1}) - {2}%" msgstr "" -#: public/js/frappe/ui/toolbar/awesome_bar.js:348 -#: public/js/frappe/ui/toolbar/awesome_bar.js:351 +#: public/js/frappe/ui/toolbar/awesome_bar.js:371 +#: public/js/frappe/ui/toolbar/awesome_bar.js:374 msgid "{0} = {1}" msgstr "" @@ -30439,7 +30921,7 @@ msgstr "" msgid "{0} is like {1}" msgstr "" -#: email/doctype/email_account/email_account.py:186 +#: email/doctype/email_account/email_account.py:187 msgid "{0} is mandatory" msgstr "" @@ -30519,7 +31001,7 @@ msgstr "" msgid "{0} is one of {1}" msgstr "" -#: email/doctype/email_account/email_account.py:293 model/naming.py:217 +#: email/doctype/email_account/email_account.py:294 model/naming.py:217 #: printing/doctype/print_format/print_format.py:91 utils/csvutils.py:153 msgid "{0} is required" msgstr "" @@ -30890,7 +31372,7 @@ msgstr "" #: contacts/doctype/address/address.js:35 #: contacts/doctype/contact/contact.js:88 -#: public/js/frappe/views/workspace/workspace.js:170 +#: public/js/frappe/views/workspace/workspace.js:211 msgid "{0}: {1}" msgstr "" @@ -30964,8 +31446,8 @@ msgstr "" msgid "{} field cannot be empty." msgstr "" -#: email/doctype/email_account/email_account.py:216 -#: email/doctype/email_account/email_account.py:224 +#: email/doctype/email_account/email_account.py:217 +#: email/doctype/email_account/email_account.py:225 msgid "{} has been disabled. It can only be enabled if {} is checked." msgstr "" @@ -30985,3 +31467,8 @@ msgstr "" msgid "{} not found in PATH! This is required to take a backup." msgstr "" +#: public/js/frappe/file_uploader/FileBrowser.vue:5 +#: public/js/frappe/file_uploader/WebLink.vue:4 +msgid "← Back to upload files" +msgstr "" + From 6eaf381dcc5c5c328db8f956b67b9df5746e280c Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 30 Jul 2024 20:22:28 +0200 Subject: [PATCH 140/176] fix: make workspace buttons translatable Resolves https://github.com/frappe/frappe/pull/27221/files#r1696441166 --- frappe/public/js/frappe/views/workspace/workspace.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index ec1f179cbc..7953e69e0d 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -99,15 +99,13 @@ frappe.views.Workspace = class Workspace { - +
    `).appendTo(this.body); From 6da35eca4570125c16112948d44fc0f76179594d Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Tue, 30 Jul 2024 21:06:12 +0200 Subject: [PATCH 141/176] fix: disable fuzzy matching while updating po files (#27257) --- frappe/gettext/translate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/gettext/translate.py b/frappe/gettext/translate.py index bf5b60f0b8..3e43e55f7a 100644 --- a/frappe/gettext/translate.py +++ b/frappe/gettext/translate.py @@ -218,7 +218,7 @@ def update_po(target_app: str | None = None, locale: str | None = None): pot_catalog = get_catalog(app) for locale in locales: po_catalog = get_catalog(app, locale) - po_catalog.update(pot_catalog) + po_catalog.update(pot_catalog, no_fuzzy_matching=True) po_path = write_catalog(app, po_catalog, locale) print(f"PO file modified at {po_path}") From 88ba015775249bbfb7e01af780daa8b6cd5e43e1 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 30 Jul 2024 21:33:13 +0200 Subject: [PATCH 142/176] fix: layout of checkboxes in print sidebar --- frappe/public/scss/desk/print_preview.scss | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frappe/public/scss/desk/print_preview.scss b/frappe/public/scss/desk/print_preview.scss index 5d7f88585b..d345a8819a 100644 --- a/frappe/public/scss/desk/print_preview.scss +++ b/frappe/public/scss/desk/print_preview.scss @@ -45,8 +45,16 @@ .layout-side-section.print-preview-sidebar { padding-right: var(--padding-md); + .checkbox label { + align-items: unset; + } + + .input-area { + margin-top: 0.2rem; + } + .label-area { - white-space: nowrap; + white-space: unset; } } From 33a84b1c23f7de45b4b6d4e1328f06f28dccdd4f Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Wed, 31 Jul 2024 12:26:08 +0530 Subject: [PATCH 143/176] fix: Email Sent Twice (#27227) * fix: Email Sent Twice * fix: Email Sent Twice * fix: Email Sent Twice --- frappe/core/doctype/user/user.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index bc339432ec..225175e417 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -362,7 +362,11 @@ class User(Document): user=self.name, pwd=new_password, logout_all_sessions=self.logout_all_sessions ) - if not self.flags.no_welcome_mail and cint(self.send_welcome_email): + if ( + not self.flags.no_welcome_mail + and cint(self.send_welcome_email) + and not self.flags.email_sent + ): self.send_welcome_mail_to_user() self.flags.email_sent = 1 if frappe.session.user != "Guest": From 43cd2ce97cbfff5354b942a1ff92b9894e540c33 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Wed, 31 Jul 2024 16:27:59 +0530 Subject: [PATCH 144/176] fix: fetch from not working in quick entry form --- frappe/public/js/frappe/form/controls/link.js | 84 +++++++++++++++++-- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index 62e5e4de67..c59d2edc7c 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -638,13 +638,18 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat if (value) { field_value = response[source_field]; } - frappe.model.set_value( - this.df.parent, - this.docname, - target_field, - field_value, - this.df.fieldtype - ); + + if (this.layout?.set_value) { + this.layout.set_value(target_field, field_value); + } else { + frappe.model.set_value( + this.df.parent, + this.docname, + target_field, + field_value, + this.df.fieldtype + ); + } } }; @@ -669,8 +674,73 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat } } + fetch_map_for_quick_entry() { + let me = this; + let fetch_map = {}; + function add_fetch(link_field, source_field, target_field, target_doctype) { + if (!target_doctype) target_doctype = "*"; + + if (!me.layout.fetch_dict) { + me.layout.fetch_dict = {}; + } + + // Target field kept as key because source field could be non-unique + me.layout.fetch_dict.setDefault(target_doctype, {}).setDefault(link_field, {})[ + target_field + ] = source_field; + } + + function setup_add_fetch(df) { + let is_read_only_field = + [ + "Data", + "Read Only", + "Text", + "Small Text", + "Currency", + "Check", + "Text Editor", + "Attach Image", + "Code", + "Link", + "Float", + "Int", + "Date", + "Select", + "Duration", + "Time", + ].includes(df.fieldtype) || + df.read_only == 1 || + df.is_virtual == 1; + + if (is_read_only_field && df.fetch_from && df.fetch_from.indexOf(".") != -1) { + var parts = df.fetch_from.split("."); + add_fetch(parts[0], parts[1], df.fieldname, df.parent); + } + } + + $.each(this.layout.fields, (i, field) => setup_add_fetch(field)); + + for (const key of ["*", this.df.parent]) { + if (!this.layout.fetch_dict) { + this.layout.fetch_dict = {}; + } + if (this.layout.fetch_dict[key] && this.layout.fetch_dict[key][this.df.fieldname]) { + Object.assign(fetch_map, this.layout.fetch_dict[key][this.df.fieldname]); + } + } + + return fetch_map; + } + get fetch_map() { const fetch_map = {}; + + // Create fetch_map from quick entry fields + if (!this.frm && this.layout && this.layout.fields) { + return this.fetch_map_for_quick_entry(); + } + if (!this.frm) return fetch_map; for (const key of ["*", this.df.parent]) { From b8e4f30e59b37fec58dd3872178d1b57ed611b6a Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 31 Jul 2024 16:52:19 +0530 Subject: [PATCH 145/176] perf: use seperate endpoint to send newsletters (#27268) --- .../email/doctype/email_queue/email_queue.py | 20 ++++-- frappe/email/frappemail.py | 63 ++++++++----------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index dbf4ba68ad..8f02a6e5f2 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -171,11 +171,18 @@ class EmailQueue(Document): method(self, self.sender, recipient.recipient, message) elif not frappe.flags.in_test or frappe.flags.testing_email: if ctx.email_account_doc.service == "Frappe Mail": - ctx.frappe_mail_client.send_raw( - sender=self.sender, - recipients=recipient.recipient, - message=message.decode("utf-8"), - ) + if self.reference_doctype == "Newsletter": + ctx.frappe_mail_client.send_newsletter( + sender=self.sender, + recipients=recipient.recipient, + message=message.decode("utf-8"), + ) + else: + ctx.frappe_mail_client.send_raw( + sender=self.sender, + recipients=recipient.recipient, + message=message.decode("utf-8"), + ) else: ctx.smtp_server.session.sendmail( from_addr=self.sender, @@ -780,7 +787,8 @@ class QueueBuilder: with suppress(Exception): q.send(smtp_server_instance=smtp_server_instance, frappe_mail_client=frappe_mail_client) - smtp_server_instance.quit() + if smtp_server_instance: + smtp_server_instance.quit() def as_dict(self, include_recipients=True): email_account = self.get_outgoing_email_account() diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index e9d792aae6..a4bcf9b5c2 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import TYPE_CHECKING +from typing import Any from urllib.parse import urljoin import pytz @@ -9,9 +9,6 @@ from frappe import _ from frappe.frappeclient import FrappeClient, FrappeOAuth2Client from frappe.utils import convert_utc_to_system_timezone, get_datetime, get_datetime_str, get_system_timezone -if TYPE_CHECKING: - from requests import Response - class FrappeMail: """Class to interact with the Frappe Mail API.""" @@ -29,6 +26,9 @@ class FrappeMail: self.api_key = api_key self.api_secret = api_secret self.access_token = access_token + self.client = self.get_client( + self.site, self.mailbox, self.api_key, self.api_secret, self.access_token + ) @staticmethod def get_client( @@ -65,64 +65,51 @@ class FrappeMail: headers: dict[str, str] | None = None, timeout: int | tuple[int, int] = (60, 120), raise_exception: bool = True, - ) -> "Response": - """Makes a HTTP request to the Frappe Mail API.""" + ) -> Any | None: + """Makes a request to the Frappe Mail API.""" - url = urljoin(self.site, endpoint) - client = self.get_client(self.site, self.mailbox, self.api_key, self.api_secret, self.access_token) + url = urljoin(self.client.url, endpoint) headers = headers or {} - headers.update(client.headers) + headers.update(self.client.headers) - response = client.session.request( + response = self.client.session.request( method=method, url=url, params=params, data=data, json=json, headers=headers, timeout=timeout ) - if not response.ok and raise_exception: - error_msg = response.text - if response.status_code == 401: - if self.access_token: - error_msg = _("Authentication Error: Reauthorize OAuth for Email Account {0}.").format( - frappe.bold(self.mailbox) - ) - else: - error_msg = _("Authentication Error: Invalid API Key or Secret") - - frappe.throw(title=_("Frappe Mail"), msg=error_msg) - - return response + return self.client.post_process(response) def validate(self, for_outbound: bool = False, for_inbound: bool = False) -> None: """Validates the mailbox for inbound and outbound emails.""" - endpoint = "auth/validate" + endpoint = "/api/method/mail.api.auth.validate" data = {"mailbox": self.mailbox, "for_outbound": for_outbound, "for_inbound": for_inbound} - response = self.request("POST", endpoint=endpoint, data=data, raise_exception=False) + self.request("POST", endpoint=endpoint, data=data) - if not response.ok: - if error_msg := response.json().get("exception"): - if error_msg == "frappe.exceptions.AuthenticationError": - error_msg += ": Invalid API Key or Secret" - - frappe.throw(title="Frappe Mail", msg=error_msg) - - def send_raw(self, sender: str, recipients: str, message: str) -> None: + def send_raw(self, sender: str, recipients: str | list, message: str) -> None: """Sends an email using the Frappe Mail API.""" - endpoint = "outbound/send-raw" - json_data = {"from": sender, "to": recipients, "raw_message": message} - self.request("POST", endpoint=endpoint, json=json_data) + endpoint = "/api/method/mail.api.outbound.send_raw" + data = {"from_": sender, "to": recipients, "raw_message": message} + self.request("POST", endpoint=endpoint, data=data) + + def send_newsletter(self, sender: str, recipients: str | list, message: str) -> None: + """Sends an newsletter using the Frappe Mail API.""" + + endpoint = "/api/method/mail.api.outbound.send_newsletter" + data = {"from_": sender, "to": recipients, "raw_message": message} + self.request("POST", endpoint=endpoint, json=data) def pull_raw(self, limit: int = 50, last_synced_at: str | None = None) -> dict[str, list[str] | str]: """Pulls emails from the mailbox using the Frappe Mail API.""" - endpoint = "inbound/pull-raw" + endpoint = "/api/method/mail.api.inbound.pull_raw" if last_synced_at: last_synced_at = convert_to_utc(last_synced_at) data = {"mailbox": self.mailbox, "limit": limit, "last_synced_at": last_synced_at} headers = {"X-Site": frappe.utils.get_url()} - response = self.request("GET", endpoint=endpoint, data=data, headers=headers).json()["message"] + response = self.request("GET", endpoint=endpoint, data=data, headers=headers) last_synced_at = convert_utc_to_system_timezone(get_datetime(response["last_synced_at"])) return {"latest_messages": response["mails"], "last_synced_at": last_synced_at} From 5e94b05a7f6baa5580fe073cff81824bc1683de8 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Wed, 31 Jul 2024 17:25:54 +0530 Subject: [PATCH 146/176] fix: set fields value if this.frm exist --- frappe/public/js/frappe/form/controls/link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index c59d2edc7c..e391706161 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -641,7 +641,7 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat if (this.layout?.set_value) { this.layout.set_value(target_field, field_value); - } else { + } else if (this.frm) { frappe.model.set_value( this.df.parent, this.docname, From cafa9fdcade68beae2b3235df1a7239406afd0c0 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 1 Aug 2024 17:01:40 +0530 Subject: [PATCH 147/176] fix: header block is not translatable --- frappe/public/js/frappe/views/workspace/blocks/header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/workspace/blocks/header.js b/frappe/public/js/frappe/views/workspace/blocks/header.js index b5b42796d4..9da404c4c7 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/header.js +++ b/frappe/public/js/frappe/views/workspace/blocks/header.js @@ -104,7 +104,7 @@ export default class Header extends Block { this._data = this.normalizeData(data); if (data.text !== undefined) { - let text = this._data.text || ""; + let text = __(this._data.text) || ""; const contains_html_tag = /<[a-z][\s\S]*>/i.test(text); this._element.innerHTML = contains_html_tag ? text From c308279158ecc4437bd613c8e43adf9d746cbadf Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Fri, 2 Aug 2024 12:05:07 +0530 Subject: [PATCH 148/176] fix: translate header inner text if it is a simple text --- frappe/public/js/frappe/views/workspace/blocks/header.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/public/js/frappe/views/workspace/blocks/header.js b/frappe/public/js/frappe/views/workspace/blocks/header.js index 9da404c4c7..072b054bad 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/header.js +++ b/frappe/public/js/frappe/views/workspace/blocks/header.js @@ -106,6 +106,14 @@ export default class Header extends Block { if (data.text !== undefined) { let text = __(this._data.text) || ""; const contains_html_tag = /<[a-z][\s\S]*>/i.test(text); + + // apply translation to header text + let div = document.createElement("div"); + div.innerHTML = text; + let only_text = div.innerText; + only_text = frappe.utils.escape_html(only_text); + text = text.replace(only_text, __(only_text)); + this._element.innerHTML = contains_html_tag ? text : `${text}`; From a44c88b0848aa066a989df1dc2d89a160cf14b01 Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:32:15 +0530 Subject: [PATCH 149/176] fix: child table filter --- frappe/public/js/frappe/form/grid_row.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index 5c0a5cbe22..a12aab162b 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -840,10 +840,12 @@ export default class GridRow { delete this.grid.filter[df.fieldname]; } - this.grid.grid_sortable.option( - "disabled", - Object.keys(this.grid.filter).length !== 0 - ); + if (this.grid.grid_sortable) { + this.grid.grid_sortable.option( + "disabled", + Object.keys(this.grid.filter).length !== 0 + ); + } this.grid.prevent_build = true; this.grid.grid_pagination.go_to_page(1); From 84fd056439a132ccee07c93af69809a172db2d49 Mon Sep 17 00:00:00 2001 From: Osama Shaikh <31347530+0samashaikh@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:18:36 +0530 Subject: [PATCH 150/176] fix: Allow track changes for Roles and Allowed Modules child tables in User DocType (#26841) * fix: Allow track changes for Roles and Allowed Modules child tables in User DocType * fix: lint * feat: config in docfield to show field in timeline * fix: enable 'Show on Timeline' only when hidden is checked --- frappe/core/doctype/docfield/docfield.json | 12 +++++++-- frappe/core/doctype/docfield/docfield.py | 1 + frappe/core/doctype/user/user.json | 8 +++--- .../version_timeline_content_builder.js | 25 ++++++++++++++----- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json index 4943f7a94c..f2d0eee7a1 100644 --- a/frappe/core/doctype/docfield/docfield.json +++ b/frappe/core/doctype/docfield/docfield.json @@ -32,6 +32,7 @@ "fetch_if_empty", "visibility_section", "hidden", + "show_on_timeline", "bold", "allow_in_quick_entry", "translatable", @@ -578,13 +579,20 @@ "fieldname": "not_nullable", "fieldtype": "Check", "label": "Not Nullable" + }, + { + "default": "0", + "depends_on": "eval: doc.hidden", + "fieldname": "show_on_timeline", + "fieldtype": "Check", + "label": "Show on Timeline" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-04-12 16:27:34.546314", + "modified": "2024-07-30 13:15:32.037892", "modified_by": "Administrator", "module": "Core", "name": "DocField", @@ -594,4 +602,4 @@ "sort_field": "creation", "sort_order": "ASC", "states": [] -} +} \ No newline at end of file diff --git a/frappe/core/doctype/docfield/docfield.py b/frappe/core/doctype/docfield/docfield.py index ed663c3bba..4dc397d5b5 100644 --- a/frappe/core/doctype/docfield/docfield.py +++ b/frappe/core/doctype/docfield/docfield.py @@ -112,6 +112,7 @@ class DocField(Document): search_index: DF.Check set_only_once: DF.Check show_dashboard: DF.Check + show_on_timeline: DF.Check sort_options: DF.Check translatable: DF.Check unique: DF.Check diff --git a/frappe/core/doctype/user/user.json b/frappe/core/doctype/user/user.json index 1cdf6c2397..4e326bbc25 100644 --- a/frappe/core/doctype/user/user.json +++ b/frappe/core/doctype/user/user.json @@ -237,7 +237,8 @@ "options": "Has Role", "permlevel": 1, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_on_timeline": 1 }, { "collapsible": 1, @@ -428,7 +429,8 @@ "hidden": 1, "label": "Block Modules", "options": "Block Module", - "permlevel": 1 + "permlevel": 1, + "show_on_timeline": 1 }, { "fieldname": "home_settings", @@ -796,7 +798,7 @@ "link_fieldname": "user" } ], - "modified": "2024-04-12 23:25:04.628007", + "modified": "2024-07-15 18:40:18.842915", "modified_by": "Administrator", "module": "Core", "name": "User", diff --git a/frappe/public/js/frappe/form/footer/version_timeline_content_builder.js b/frappe/public/js/frappe/form/footer/version_timeline_content_builder.js index 03936d9a1f..43d55fe5da 100644 --- a/frappe/public/js/frappe/form/footer/version_timeline_content_builder.js +++ b/frappe/public/js/frappe/form/footer/version_timeline_content_builder.js @@ -83,13 +83,17 @@ function get_version_timeline_content(version_doc, frm) { } } else { const df = frappe.meta.get_docfield(frm.doctype, p[0], frm.docname); - if (df && !df.hidden) { + if (df && (!df.hidden || df.show_on_timeline)) { const field_display_status = frappe.perm.get_field_display_status( df, null, frm.perm ); - if (field_display_status === "Read" || field_display_status === "Write") { + if ( + field_display_status === "Read" || + field_display_status === "Write" || + (df.hidden && df.show_on_timeline) + ) { parts.push( __("{0} from {1} to {2}", [ __(df.label, null, df.parent), @@ -142,14 +146,18 @@ function get_version_timeline_content(version_doc, frm) { frm.docname ); - if (df && !df.hidden) { + if (df && (!df.hidden || df.show_on_timeline)) { var field_display_status = frappe.perm.get_field_display_status( df, null, frm.perm ); - if (field_display_status === "Read" || field_display_status === "Write") { + if ( + field_display_status === "Read" || + field_display_status === "Write" || + (df.hidden && df.show_on_timeline) + ) { parts.push( __("{0} from {1} to {2} in row #{3}", [ frappe.meta.get_label(frm.fields_dict[row[0]].grid.doctype, p[0]), @@ -197,14 +205,19 @@ function get_version_timeline_content(version_doc, frm) { if (data[key] && data[key].length) { let parts = (data[key] || []).map(function (p) { var df = frappe.meta.get_docfield(frm.doctype, p[0], frm.docname); - if (df && !df.hidden) { + + if (df && (!df.hidden || df.show_on_timeline)) { var field_display_status = frappe.perm.get_field_display_status( df, null, frm.perm ); - if (field_display_status === "Read" || field_display_status === "Write") { + if ( + field_display_status === "Read" || + field_display_status === "Write" || + (df.hidden && df.show_on_timeline) + ) { return __(frappe.meta.get_label(frm.doctype, p[0])); } } From e9e327104db7beb247d320e9f30e6e92e2b07e4b Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sat, 3 Aug 2024 09:35:15 +0530 Subject: [PATCH 151/176] fix: get value with ignore=True --- .../doctype/notification_settings/notification_settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/desk/doctype/notification_settings/notification_settings.py b/frappe/desk/doctype/notification_settings/notification_settings.py index 41a6991d6f..691c03588d 100644 --- a/frappe/desk/doctype/notification_settings/notification_settings.py +++ b/frappe/desk/doctype/notification_settings/notification_settings.py @@ -59,9 +59,10 @@ def is_email_notifications_enabled_for_type(user, notification_type): return False fieldname = "enable_email_" + frappe.scrub(notification_type) - enabled = frappe.db.get_value("Notification Settings", user, fieldname) + enabled = frappe.db.get_value("Notification Settings", user, fieldname, ignore=True) if enabled is None: return True + return enabled From 20224011b8ffdc72e6e01eb19f149bea2b367d64 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sat, 3 Aug 2024 10:48:17 +0530 Subject: [PATCH 152/176] fix: default notification --- frappe/desk/doctype/notification_log/notification_log.json | 4 ++-- frappe/desk/doctype/notification_log/notification_log.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/desk/doctype/notification_log/notification_log.json b/frappe/desk/doctype/notification_log/notification_log.json index 49b16266b4..c3b3c09d92 100644 --- a/frappe/desk/doctype/notification_log/notification_log.json +++ b/frappe/desk/doctype/notification_log/notification_log.json @@ -40,7 +40,7 @@ "in_list_view": 1, "in_standard_filter": 1, "label": "Type", - "options": "Mention\nEnergy Point\nAssignment\nShare\nAlert" + "options": "\nMention\nEnergy Point\nAssignment\nShare\nAlert" }, { "fieldname": "email_content", @@ -103,7 +103,7 @@ "hide_toolbar": 1, "in_create": 1, "links": [], - "modified": "2024-03-23 16:03:31.715461", + "modified": "2024-08-03 09:38:10.497711", "modified_by": "Administrator", "module": "Desk", "name": "Notification Log", diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py index 8793559611..499e4e27cd 100644 --- a/frappe/desk/doctype/notification_log/notification_log.py +++ b/frappe/desk/doctype/notification_log/notification_log.py @@ -28,7 +28,7 @@ class NotificationLog(Document): link: DF.Data | None read: DF.Check subject: DF.Text | None - type: DF.Literal["Mention", "Energy Point", "Assignment", "Share", "Alert"] + type: DF.Literal["", "Mention", "Energy Point", "Assignment", "Share", "Alert"] # end: auto-generated types def after_insert(self): From 774d86f642627dda026ac37b333db2805ada6837 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sun, 4 Aug 2024 13:41:08 +0530 Subject: [PATCH 153/176] feat: Workspace Settings - allow enabling and disabling of workspaces during setup --- frappe/core/doctype/doctype/doctype.json | 28 +++--- .../navbar_settings/navbar_settings.py | 31 ++++++ frappe/core/workspace/users/users.json | 3 +- frappe/desk/desktop.py | 17 +++- .../doctype/workspace_settings/__init__.py | 0 .../test_workspace_settings.py | 9 ++ .../workspace_settings/workspace_settings.js | 35 +++++++ .../workspace_settings.json | 56 +++++++++++ .../workspace_settings/workspace_settings.py | 21 ++++ frappe/hooks.py | 10 +- frappe/migrate.py | 2 + frappe/model/base_document.py | 19 +++- frappe/patches.txt | 2 + .../js/frappe/form/controls/base_input.js | 5 + frappe/public/js/frappe/form/quick_entry.js | 95 ++++++++++++------- .../public/js/frappe/form/script_manager.js | 11 ++- frappe/public/js/frappe/ui/dialog.js | 14 +++ .../js/frappe/views/workspace/workspace.js | 13 ++- 18 files changed, 309 insertions(+), 62 deletions(-) create mode 100644 frappe/desk/doctype/workspace_settings/__init__.py create mode 100644 frappe/desk/doctype/workspace_settings/test_workspace_settings.py create mode 100644 frappe/desk/doctype/workspace_settings/workspace_settings.js create mode 100644 frappe/desk/doctype/workspace_settings/workspace_settings.json create mode 100644 frappe/desk/doctype/workspace_settings/workspace_settings.py diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json index c285c6ffec..6979dd35fc 100644 --- a/frappe/core/doctype/doctype/doctype.json +++ b/frappe/core/doctype/doctype/doctype.json @@ -10,6 +10,11 @@ "field_order": [ "form_builder_tab", "form_builder", + "permissions_tab", + "permissions", + "restrict_to_domain", + "read_only", + "in_create", "settings_tab", "sb0", "module", @@ -70,11 +75,6 @@ "sender_field", "sender_name_field", "subject_field", - "sb2", - "permissions", - "restrict_to_domain", - "read_only", - "in_create", "actions_section", "actions", "links_section", @@ -152,8 +152,8 @@ }, { "default": "0", - "depends_on": "eval:!doc.istable && !doc.issingle", - "description": "Open a dialog with mandatory fields to create a new record quickly", + "depends_on": "eval:!doc.istable", + "description": "Open a dialog with mandatory fields to create a new record quickly. There must be at least one mandatory field to show in dialog.", "fieldname": "quick_entry", "fieldtype": "Check", "label": "Quick Entry" @@ -381,12 +381,6 @@ "fieldtype": "Check", "label": "Make \"name\" searchable in Global Search" }, - { - "depends_on": "eval:!doc.istable", - "fieldname": "sb2", - "fieldtype": "Section Break", - "label": "Permission Rules" - }, { "fieldname": "permissions", "fieldtype": "Table", @@ -418,6 +412,7 @@ "oldfieldtype": "Check" }, { + "collapsible": 1, "depends_on": "eval:doc.custom===0 && !doc.istable", "fieldname": "web_view", "fieldtype": "Section Break", @@ -668,6 +663,11 @@ "fieldname": "sender_name_field", "fieldtype": "Data", "label": "Sender Name Field" + }, + { + "fieldname": "permissions_tab", + "fieldtype": "Tab Break", + "label": "Permissions" } ], "icon": "fa fa-bolt", @@ -750,7 +750,7 @@ "link_fieldname": "reference_doctype" } ], - "modified": "2024-03-29 16:09:26.114720", + "modified": "2024-08-02 14:48:12.911702", "modified_by": "Administrator", "module": "Core", "name": "DocType", diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py index b155b530ed..68223f299f 100644 --- a/frappe/core/doctype/navbar_settings/navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/navbar_settings.py @@ -53,3 +53,34 @@ def get_app_logo(): def get_navbar_settings(): return frappe.get_single("Navbar Settings") + + +def sync_standard_items(): + """Syncs standard items from hooks. Called in migrate""" + + sync_table("settings_dropdown", "standard_navbar_items") + sync_table("help_dropdown", "standard_help_items") + + +def sync_table(key, hook): + navbar_settings = NavbarSettings("Navbar Settings") + existing_items = {d.item_label: d for d in navbar_settings.get(key)} + new_items = {} + + # add new items + count = 0 # matain count because list may come from seperate apps + for item in frappe.get_hooks(hook): + if item.get("item_label") not in existing_items: + navbar_settings.append(key, item, count) + new_items[item.get("item_label")] = True + count += 1 + + # remove unused items + def fn(item): + if item.is_standard and (item.item_label not in new_items): + return False + else: + return True + + navbar_settings.set(key, filter(lambda item: fn, navbar_settings.get(key))) + navbar_settings.save() diff --git a/frappe/core/workspace/users/users.json b/frappe/core/workspace/users/users.json index 3899ad534b..a84facecff 100644 --- a/frappe/core/workspace/users/users.json +++ b/frappe/core/workspace/users/users.json @@ -103,6 +103,7 @@ "link_to": "Document Share Report", "link_type": "Report", "onboard": 0, + "report_ref_doctype": "DocShare", "type": "Link" }, { @@ -158,7 +159,7 @@ "type": "Link" } ], - "modified": "2024-01-02 15:39:13.811700", + "modified": "2024-08-03 13:14:36.129599", "modified_by": "Administrator", "module": "Core", "name": "Users", diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index 71d29a2579..211820be28 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -3,7 +3,7 @@ # Author - Shivam Mishra from functools import wraps -from json import dumps, loads +from json import JSONDecodeError, dumps, loads import frappe from frappe import DoesNotExistError, ValidationError, _, _dict @@ -450,6 +450,14 @@ def get_workspace_sidebar_items(): pages = [] private_pages = [] + # get additional settings from Work Settings + try: + workspace_visibilty = loads( + frappe.db.get_single_value("Workspace Settings", "workspace_visibility_json") or "{}" + ) + except JSONDecodeError: + workspace_visibilty = {} + # Filter Page based on Permission for page in all_pages: try: @@ -460,6 +468,10 @@ def get_workspace_sidebar_items(): elif page.for_user == frappe.session.user: private_pages.append(page) page["label"] = _(page.get("name")) + + if page["name"] in workspace_visibilty: + page["visibility"] = workspace_visibilty[page["name"]] + except frappe.PermissionError: pass if private_pages: @@ -470,6 +482,9 @@ def get_workspace_sidebar_items(): pages[0]["label"] = _("Welcome Workspace") return { + "workspace_setup_completed": frappe.db.get_single_value( + "Workspace Settings", "workspace_setup_completed" + ), "pages": pages, "has_access": has_access, "has_create_access": frappe.has_permission(doctype="Workspace", ptype="create"), diff --git a/frappe/desk/doctype/workspace_settings/__init__.py b/frappe/desk/doctype/workspace_settings/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/desk/doctype/workspace_settings/test_workspace_settings.py b/frappe/desk/doctype/workspace_settings/test_workspace_settings.py new file mode 100644 index 0000000000..fe639c4d1c --- /dev/null +++ b/frappe/desk/doctype/workspace_settings/test_workspace_settings.py @@ -0,0 +1,9 @@ +# Copyright (c) 2024, Frappe Technologies and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestWorkspaceSettings(FrappeTestCase): + pass diff --git a/frappe/desk/doctype/workspace_settings/workspace_settings.js b/frappe/desk/doctype/workspace_settings/workspace_settings.js new file mode 100644 index 0000000000..5a8525b80c --- /dev/null +++ b/frappe/desk/doctype/workspace_settings/workspace_settings.js @@ -0,0 +1,35 @@ +// Copyright (c) 2024, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Workspace Settings", { + setup(frm) { + frm.hide_full_form_button = true; + frm.docfields = []; + let workspace_visibilty = JSON.parse(frm.doc.workspace_visibility_json || "{}"); + + // build fields from workspaces + for (let w of frappe.boot.allowed_workspaces) { + if (w.public) { + frm.docfields.push({ + fieldtype: "Check", + fieldname: w.name, + label: w.title, + initial_value: workspace_visibilty[w.name] !== 0, // not set is also visible + }); + } + } + + frappe.temp = frm; + }, + validate(frm) { + frm.doc.workspace_visibility_json = JSON.stringify(frm.dialog.get_values()); + frm.doc.workspace_setup_completed = 1; + }, + after_save(frm) { + // reload page to show latest sidebar + window.location.reload(); + }, + refresh(frm) { + frm.dialog.set_alert(__("Select modules you want to see in the sidebar")); + }, +}); diff --git a/frappe/desk/doctype/workspace_settings/workspace_settings.json b/frappe/desk/doctype/workspace_settings/workspace_settings.json new file mode 100644 index 0000000000..d5a86559a5 --- /dev/null +++ b/frappe/desk/doctype/workspace_settings/workspace_settings.json @@ -0,0 +1,56 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2024-08-02 14:20:30.177818", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "select_workspaces_section", + "workspace_visibility_json", + "workspace_setup_completed" + ], + "fields": [ + { + "fieldname": "select_workspaces_section", + "fieldtype": "Section Break", + "label": "Select Workspaces" + }, + { + "fieldname": "workspace_visibility_json", + "fieldtype": "JSON", + "in_list_view": 1, + "label": "Workspace Visibility", + "reqd": 1 + }, + { + "default": "0", + "fieldname": "workspace_setup_completed", + "fieldtype": "Check", + "label": "Workspace Setup Completed" + } + ], + "index_web_pages_for_search": 1, + "issingle": 1, + "links": [], + "modified": "2024-08-03 19:34:16.757871", + "modified_by": "Administrator", + "module": "Desk", + "name": "Workspace Settings", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "quick_entry": 1, + "sort_field": "creation", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/frappe/desk/doctype/workspace_settings/workspace_settings.py b/frappe/desk/doctype/workspace_settings/workspace_settings.py new file mode 100644 index 0000000000..7909a37c1e --- /dev/null +++ b/frappe/desk/doctype/workspace_settings/workspace_settings.py @@ -0,0 +1,21 @@ +# Copyright (c) 2024, Frappe Technologies and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class WorkspaceSettings(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + workspace_setup_completed: DF.Check + workspace_visibility_json: DF.JSON + # end: auto-generated types + + pass diff --git a/frappe/hooks.py b/frappe/hooks.py index 74c3a7a974..2c084bbe6a 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -460,15 +460,15 @@ export_python_type_annotations = True standard_navbar_items = [ { - "item_label": "My Profile", - "item_type": "Route", - "route": "/app/user-profile", + "item_label": "User Settings", + "item_type": "Action", + "action": "frappe.ui.toolbar.route_to_user()", "is_standard": 1, }, { - "item_label": "My Settings", + "item_label": "Workspace Settings", "item_type": "Action", - "action": "frappe.ui.toolbar.route_to_user()", + "action": "frappe.quick_edit('Workspace Settings')", "is_standard": 1, }, { diff --git a/frappe/migrate.py b/frappe/migrate.py index 8afdd765f3..b6ebf00a2b 100644 --- a/frappe/migrate.py +++ b/frappe/migrate.py @@ -13,6 +13,7 @@ import frappe.modules.patch_handler import frappe.translate from frappe.cache_manager import clear_global_cache from frappe.core.doctype.language.language import sync_languages +from frappe.core.doctype.navbar_settings.navbar_settings import sync_standard_items from frappe.core.doctype.scheduled_job_type.scheduled_job_type import sync_jobs from frappe.database.schema import add_column from frappe.deferred_insert import save_to_db as flush_deferred_inserts @@ -141,6 +142,7 @@ class SiteMigration: print("Syncing fixtures...") sync_fixtures() + sync_standard_items() print("Syncing dashboards...") sync_dashboards() diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 595730858b..43e88ffced 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -252,7 +252,7 @@ class BaseDocument: if key in self.__dict__: del self.__dict__[key] - def append(self, key: str, value: D | dict | None = None) -> D: + def append(self, key: str, value: D | dict | None = None, position: int = -1) -> D: """Append an item to a child table. Example: @@ -268,13 +268,22 @@ class BaseDocument: if (table := self.__dict__.get(key)) is None: self.__dict__[key] = table = [] - ret_value = self._init_child(value, key) - table.append(ret_value) + d = self._init_child(value, key) + + if position == -1: + table.append(d) + else: + # insert at specific position + table.insert(position, d) + + # re number idx + for i, _d in enumerate(table): + _d.idx = i + 1 # reference parent document but with weak reference, parent_doc will be deleted if self is garbage collected. - ret_value.parent_doc = weakref.ref(self) + d.parent_doc = weakref.ref(self) - return ret_value + return d @property def parent_doc(self): diff --git a/frappe/patches.txt b/frappe/patches.txt index a937f535fc..275e667a49 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -237,3 +237,5 @@ frappe.patches.v15_0.migrate_session_data frappe.custom.doctype.property_setter.patches.remove_invalid_fetch_from_expressions frappe.patches.v16_0.switch_default_sort_order frappe.integrations.doctype.oauth_client.patches.set_default_allowed_role_in_oauth_client +execute:frappe.db.set_single_value("Website Settings", "workspace_setup_completed", 1) + diff --git a/frappe/public/js/frappe/form/controls/base_input.js b/frappe/public/js/frappe/form/controls/base_input.js index 22958701be..fcb1a8ad31 100644 --- a/frappe/public/js/frappe/form/controls/base_input.js +++ b/frappe/public/js/frappe/form/controls/base_input.js @@ -7,6 +7,11 @@ frappe.ui.form.ControlInput = class ControlInput extends frappe.ui.form.Control // set description this.set_max_width(); + + // set initial value if set + if (this.df.initial_value) { + this.set_value(this.df.initial_value); + } } make_wrapper() { if (this.only_input) { diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 662891eccc..1a535ce666 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -1,6 +1,7 @@ frappe.provide("frappe.ui.form"); frappe.quick_edit = function (doctype, name) { + if (!name) name = doctype; // single frappe.db.get_doc(doctype, name).then((doc) => { frappe.ui.form.make_quick_entry(doctype, null, null, doc); }); @@ -39,6 +40,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { this.check_quick_entry_doc(); this.set_meta_and_mandatory_fields(); if (this.is_quick_entry() || this.force) { + this.setup_script_manager(); this.render_dialog(); resolve(this); } else { @@ -60,7 +62,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { this.meta = frappe.get_meta(this.doctype); let fields = this.meta.fields; - this.mandatory = fields.filter((df) => { + this.docfields = fields.filter((df) => { return ( (df.reqd || df.allow_in_quick_entry) && !df.read_only && @@ -83,7 +85,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { this.validate_for_prompt_autoname(); - if (this.has_child_table() || !this.mandatory.length) { + if (this.has_child_table() || !this.docfields.length) { return false; } @@ -91,7 +93,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { } too_many_mandatory_fields() { - if (this.mandatory.length > 7) { + if (this.docfields.length > 7) { // too many fields, show form return true; } @@ -100,7 +102,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { has_child_table() { if ( - $.map(this.mandatory, function (d) { + $.map(this.docfields, function (d) { return d.fieldtype === "Table" ? d : null; }).length ) { @@ -112,38 +114,36 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { validate_for_prompt_autoname() { if (this.meta.autoname && this.meta.autoname.toLowerCase() === "prompt") { - this.mandatory = [ + this.docfields = [ { fieldname: "__newname", label: __("{0} Name", [__(this.meta.name)]), reqd: 1, fieldtype: "Data", }, - ].concat(this.mandatory); + ].concat(this.docfields); } } + setup_script_manager() { + this.script_manager = new frappe.ui.form.ScriptManager({ + frm: this, + }); + this.script_manager.setup(); + } + render_dialog() { var me = this; + this.dialog = new frappe.ui.Dialog({ - title: __("New {0}", [__(this.doctype)]), - fields: this.mandatory, + title: this.get_title(), + fields: this.docfields, doc: this.doc, }); this.register_primary_action(); - !this.force && this.render_edit_in_full_page_link(); - // ctrl+enter to save - this.dialog.wrapper.keydown(function (e) { - if ((e.ctrlKey || e.metaKey) && e.which == 13) { - if (!frappe.request.ajax_count) { - // not already working -- double entry - me.dialog.get_primary_btn().trigger("click"); - e.preventDefault(); - return false; - } - } - }); + this.render_edit_in_full_page_link(); + this.setup_cmd_enter_for_save(); this.dialog.onhide = () => (frappe.quick_entry = null); this.dialog.show(); @@ -151,11 +151,23 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { this.dialog.refresh_dependency(); this.set_defaults(); + this.script_manager.trigger("refresh"); + if (this.init_callback) { this.init_callback(this.dialog); } } + get_title() { + if (this.title) { + return this.title; + } else if (this.meta.issingle) { + return __(this.doctype); + } else { + return __("New {0}", [__(this.doctype)]); + } + } + register_primary_action() { var me = this; this.dialog.set_primary_action(__("Save"), function () { @@ -166,16 +178,15 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { if (data) { me.dialog.working = true; - me.insert().then(() => { - let messagetxt = __("New {0} {1} created", [ - __(me.doctype), - this.doc.name.bold(), - ]); - me.dialog.animation_speed = "slow"; - me.dialog.hide(); - setTimeout(function () { - frappe.show_alert({ message: messagetxt, indicator: "green" }, 3); - }, 500); + me.script_manager.trigger("validate").then(() => { + me.insert().then(() => { + let messagetxt = __("{1} saved", [__(me.doctype), this.doc.name.bold()]); + me.dialog.animation_speed = "slow"; + me.dialog.hide(); + setTimeout(function () { + frappe.show_alert({ message: messagetxt, indicator: "green" }, 3); + }, 500); + }); }); } }); @@ -238,7 +249,9 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { // delete the old doc frappe.model.clear_doc(this.dialog.doc.doctype, this.dialog.doc.name); this.dialog.doc = r.message; - if (frappe._from_link) { + if (this.script_manager.has_handler("after_save")) { + return this.script_manager.trigger("after_save"); + } else if (frappe._from_link) { frappe.ui.form.update_calling_link(this.dialog.doc); } else if (this.after_insert) { this.after_insert(this.dialog.doc); @@ -247,7 +260,23 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { } } + setup_cmd_enter_for_save() { + var me = this; + // ctrl+enter to save + this.dialog.wrapper.keydown(function (e) { + if ((e.ctrlKey || e.metaKey) && e.which == 13) { + if (!frappe.request.ajax_count) { + // not already working -- double entry + me.dialog.get_primary_btn().trigger("click"); + e.preventDefault(); + return false; + } + } + }); + } + open_form_if_not_list() { + if (this.meta.issingle) return; let route = frappe.get_route(); let doc = this.dialog.doc; if (route && !(route[0] === "List" && route[1] === doc.doctype)) { @@ -279,8 +308,8 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { } render_edit_in_full_page_link() { - var me = this; - this.dialog.add_custom_action(__("Edit Full Form"), () => me.open_doc(true)); + if (this.force || this.hide_full_form_button) return; + this.dialog.add_custom_action(__("Edit Full Form"), () => this.open_doc(true)); } set_defaults() { diff --git a/frappe/public/js/frappe/form/script_manager.js b/frappe/public/js/frappe/form/script_manager.js index 1d56a15232..badce4460f 100644 --- a/frappe/public/js/frappe/form/script_manager.js +++ b/frappe/public/js/frappe/form/script_manager.js @@ -140,6 +140,13 @@ frappe.ui.form.ScriptManager = class ScriptManager { // run them serially return frappe.run_serially(tasks); } + has_handler(event_name) { + // return true if there exist an event handler (new style only) + return ( + frappe.ui.form.handlers[this.frm.doctype] && + frappe.ui.form.handlers[this.frm.doctype][event_name] + ); + } has_handlers(event_name, doctype) { let handlers = this.get_handlers(event_name, doctype); return handlers && (handlers.old_style.length || handlers.new_style.length); @@ -156,10 +163,10 @@ frappe.ui.form.ScriptManager = class ScriptManager { handlers.new_style.push(fn); }); } - if (this.frm.cscript[event_name]) { + if (this.frm.cscript && this.frm.cscript[event_name]) { handlers.old_style.push(event_name); } - if (this.frm.cscript["custom_" + event_name]) { + if (this.frm.cscript && this.frm.cscript["custom_" + event_name]) { handlers.old_style.push("custom_" + event_name); } return handlers; diff --git a/frappe/public/js/frappe/ui/dialog.js b/frappe/public/js/frappe/ui/dialog.js index 90e95ef92b..eea34bb65e 100644 --- a/frappe/public/js/frappe/ui/dialog.js +++ b/frappe/public/js/frappe/ui/dialog.js @@ -164,6 +164,20 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { return this.$wrapper.find(".modal-header .btn-modal-minimize"); } + set_alert(text, alert_class = "info") { + this.clear_alert(); + this.$alert = $(`
    ${text}
    `).prependTo( + this.body + ); + this.$message.text(text); + } + + clear_alert() { + if (this.$alert) { + this.$alert.remove(); + } + } + set_message(text) { this.$message.removeClass("hide"); this.$body.addClass("hide"); diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index 7953e69e0d..0311bc976c 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -70,6 +70,9 @@ frappe.views.Workspace = class Workspace { this.all_pages = this.sidebar_pages.pages; this.has_access = this.sidebar_pages.has_access; this.has_create_access = this.sidebar_pages.has_create_access; + if (!this.sidebar_pages.workspace_setup_completed) { + frappe.quick_edit("Workspace Settings"); + } this.all_pages.forEach((page) => { page.is_editable = !page.public || this.has_access; @@ -80,11 +83,14 @@ frappe.views.Workspace = class Workspace { if (this.all_pages) { frappe.workspaces = {}; + frappe.workspace_list = []; for (let page of this.all_pages) { frappe.workspaces[frappe.router.slug(page.name)] = { title: page.title, public: page.public, }; + + frappe.workspace_list.push(page); } this.make_sidebar(); reload && this.show(); @@ -240,7 +246,12 @@ frappe.views.Workspace = class Workspace { } prepare_sidebar(items, child_container, item_container) { - items.forEach((item) => this.append_item(item, child_container)); + for (let item of items) { + // visibility not explicitly set to 0 + if (item.visibility !== 0) { + this.append_item(item, child_container); + } + } child_container.appendTo(item_container); } From ac4b67079278bb2edec2e1969fc25d6a2e444fd5 Mon Sep 17 00:00:00 2001 From: "El-Shafei H." Date: Sun, 4 Aug 2024 15:12:58 +0300 Subject: [PATCH 154/176] fix: add translation function to route label text (#27175) Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com> --- frappe/public/js/frappe/utils/utils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 7b6987aa05..ff534141af 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -918,18 +918,18 @@ Object.assign(frappe.utils, { let route = route_str.split("/"); if (route[2] === "Report" || route[0] === "query-report") { - return __("{0} Report", [route[3] || route[1]]); + return __("{0} Report", [__(route[3]) || __(route[1])]); } if (route[0] === "List") { - return __("{0} List", [route[1]]); + return __("{0} List", [__(route[1])]); } if (route[0] === "modules") { - return __("{0} Modules", [route[1]]); + return __("{0} Modules", [__(route[1])]); } if (route[0] === "dashboard") { - return __("{0} Dashboard", [route[1]]); + return __("{0} Dashboard", [__(route[1])]); } - return __(frappe.utils.to_title_case(route[0], true)); + return __(frappe.utils.to_title_case(__(route[0]), true)); }, report_column_total: function (values, column, type) { if (column.column.disable_total) { From c06a854ea8335354a1ae85e1704ad264a63c7436 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Sun, 4 Aug 2024 21:09:39 +0530 Subject: [PATCH 155/176] chore: update POT file (#27300) --- frappe/locale/main.pot | 825 ++++++++++++----------------------------- 1 file changed, 241 insertions(+), 584 deletions(-) diff --git a/frappe/locale/main.pot b/frappe/locale/main.pot index 044b40a645..4836eaadcd 100644 --- a/frappe/locale/main.pot +++ b/frappe/locale/main.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Frappe Framework VERSION\n" "Report-Msgid-Bugs-To: developers@frappe.io\n" -"POT-Creation-Date: 2024-07-30 18:02+0000\n" -"PO-Revision-Date: 2024-07-30 18:02+0000\n" +"POT-Creation-Date: 2024-08-04 09:33+0000\n" +"PO-Revision-Date: 2024-08-04 09:33+0000\n" "Last-Translator: developers@frappe.io\n" "Language-Team: developers@frappe.io\n" "MIME-Version: 1.0\n" @@ -749,13 +749,9 @@ msgid "About Us" msgstr "" #. Name of a DocType -#: website/doctype/about_us_settings/about_us_settings.json -msgid "About Us Settings" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/about_us_settings/about_us_settings.json #: website/workspace/website/website.json -msgctxt "About Us Settings" msgid "About Us Settings" msgstr "" @@ -788,13 +784,8 @@ msgid "Access Key Secret" msgstr "" #. Name of a DocType -#: core/doctype/access_log/access_log.json -msgid "Access Log" -msgstr "" - #. Label of a Link in the Users Workspace -#: core/workspace/users/users.json -msgctxt "Access Log" +#: core/doctype/access_log/access_log.json core/workspace/users/users.json msgid "Access Log" msgstr "" @@ -967,14 +958,10 @@ msgid "Activity" msgstr "" #. Name of a DocType -#: core/doctype/activity_log/activity_log.json -msgid "Activity Log" -msgstr "" - #. Label of a Link in the Build Workspace #. Label of a Link in the Users Workspace -#: core/workspace/build/build.json core/workspace/users/users.json -msgctxt "Activity Log" +#: core/doctype/activity_log/activity_log.json core/workspace/build/build.json +#: core/workspace/users/users.json msgid "Activity Log" msgstr "" @@ -1107,7 +1094,7 @@ msgstr "" msgid "Add Review" msgstr "" -#: core/doctype/user/user.py:772 +#: core/doctype/user/user.py:776 msgid "Add Roles" msgstr "" @@ -1394,11 +1381,11 @@ msgstr "" msgid "Administrator" msgstr "" -#: core/doctype/user/user.py:1176 +#: core/doctype/user/user.py:1180 msgid "Administrator Logged In" msgstr "" -#: core/doctype/user/user.py:1170 +#: core/doctype/user/user.py:1174 msgid "Administrator accessed {0} on {1} via IP Address {2}." msgstr "" @@ -1876,7 +1863,7 @@ msgstr "" msgid "Allowing DocType, DocType. Be careful!" msgstr "" -#: core/doctype/user/user.py:979 +#: core/doctype/user/user.py:983 msgid "Already Registered" msgstr "" @@ -2259,7 +2246,7 @@ msgstr "" msgid "Are you sure you want to delete all rows?" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:928 +#: public/js/frappe/views/workspace/workspace.js:926 msgid "Are you sure you want to delete page {0}?" msgstr "" @@ -2448,16 +2435,11 @@ msgid "Assignment Days" msgstr "" #. Name of a DocType -#. Label of the assignment_rule (Link) field in DocType 'ToDo' -#: automation/doctype/assignment_rule/assignment_rule.json -#: desk/doctype/todo/todo.json -msgid "Assignment Rule" -msgstr "" - #. Label of a Link in the Tools Workspace #. Label of a shortcut in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Assignment Rule" +#. Label of the assignment_rule (Link) field in DocType 'ToDo' +#: automation/doctype/assignment_rule/assignment_rule.json +#: automation/workspace/tools/tools.json desk/doctype/todo/todo.json msgid "Assignment Rule" msgstr "" @@ -2679,14 +2661,6 @@ msgstr "" msgid "Authentication Apps you can use are: " msgstr "" -#: email/frappemail.py:89 -msgid "Authentication Error: Invalid API Key or Secret" -msgstr "" - -#: email/frappemail.py:85 -msgid "Authentication Error: Reauthorize OAuth for Email Account {0}." -msgstr "" - #: email/doctype/email_account/email_account.py:329 msgid "Authentication failed while receiving emails from Email Account: {0}." msgstr "" @@ -2776,14 +2750,10 @@ msgstr "" msgid "Auto" msgstr "" -#. Name of a DocType -#: email/doctype/auto_email_report/auto_email_report.json -msgid "Auto Email Report" -msgstr "" - #. Label of a Link in the Tools Workspace +#. Name of a DocType #: automation/workspace/tools/tools.json -msgctxt "Auto Email Report" +#: email/doctype/auto_email_report/auto_email_report.json msgid "Auto Email Report" msgstr "" @@ -2795,14 +2765,9 @@ msgid "Auto Name" msgstr "" #. Name of a DocType -#: automation/doctype/auto_repeat/auto_repeat.json -#: public/js/frappe/utils/common.js:442 -msgid "Auto Repeat" -msgstr "" - #. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Auto Repeat" +#: automation/doctype/auto_repeat/auto_repeat.json +#: automation/workspace/tools/tools.json public/js/frappe/utils/common.js:442 msgid "Auto Repeat" msgstr "" @@ -3076,19 +3041,15 @@ msgstr "" msgid "Background Image" msgstr "" +#. Label of a Link in the Build Workspace #. Label of the background_jobs_section (Section Break) field in DocType #. 'System Health Report' +#: core/workspace/build/build.json #: desk/doctype/system_health_report/system_health_report.json #: public/js/frappe/ui/toolbar/toolbar.js:178 msgid "Background Jobs" msgstr "" -#. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "RQ Job" -msgid "Background Jobs" -msgstr "" - #. Label of the background_jobs_check (Data) field in DocType 'System Health #. Report' #: desk/doctype/system_health_report/system_health_report.json @@ -3397,14 +3358,10 @@ msgstr "" #. Name of a DocType #. Label of the blog_category (Link) field in DocType 'Blog Post' +#. Label of a Link in the Website Workspace #: website/doctype/blog_category/blog_category.json #: website/doctype/blog_post/blog_post.json -msgid "Blog Category" -msgstr "" - -#. Label of a Link in the Website Workspace #: website/workspace/website/website.json -msgctxt "Blog Category" msgid "Blog Category" msgstr "" @@ -3419,14 +3376,10 @@ msgid "Blog Introduction" msgstr "" #. Name of a DocType -#: website/doctype/blog_post/blog_post.json -msgid "Blog Post" -msgstr "" - #. Label of a Link in the Website Workspace #. Label of a shortcut in the Website Workspace +#: website/doctype/blog_post/blog_post.json #: website/workspace/website/website.json -msgctxt "Blog Post" msgid "Blog Post" msgstr "" @@ -3443,17 +3396,12 @@ msgstr "" #. Name of a role #. Label of the blogger (Link) field in DocType 'Blog Post' #. Name of a DocType +#. Label of a Link in the Website Workspace +#. Label of a shortcut in the Website Workspace #: website/doctype/blog_category/blog_category.json #: website/doctype/blog_post/blog_post.json #: website/doctype/blog_settings/blog_settings.json -#: website/doctype/blogger/blogger.json -msgid "Blogger" -msgstr "" - -#. Label of a Link in the Website Workspace -#. Label of a shortcut in the Website Workspace -#: website/workspace/website/website.json -msgctxt "Blogger" +#: website/doctype/blogger/blogger.json website/workspace/website/website.json msgid "Blogger" msgstr "" @@ -3647,14 +3595,10 @@ msgstr "" msgid "Bulk PDF Export" msgstr "" -#. Name of a DocType -#: desk/doctype/bulk_update/bulk_update.json -msgid "Bulk Update" -msgstr "" - #. Label of a Link in the Tools Workspace +#. Name of a DocType #: automation/workspace/tools/tools.json -msgctxt "Bulk Update" +#: desk/doctype/bulk_update/bulk_update.json msgid "Bulk Update" msgstr "" @@ -3826,19 +3770,14 @@ msgstr "" msgid "Calculate" msgstr "" +#. Label of a Link in the Tools Workspace #. Option for the 'Select List View' (Select) field in DocType 'Form Tour' #. Option for the 'DocType View' (Select) field in DocType 'Workspace Shortcut' -#: desk/doctype/form_tour/form_tour.json +#: automation/workspace/tools/tools.json desk/doctype/form_tour/form_tour.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json msgid "Calendar" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Event" -msgid "Calendar" -msgstr "" - #. Label of the calendar_name (Data) field in DocType 'Google Calendar' #: integrations/doctype/google_calendar/google_calendar.json msgid "Calendar Name" @@ -4514,7 +4453,7 @@ msgstr "" msgid "Choose Existing Card or create New Card" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1428 +#: public/js/frappe/views/workspace/workspace.js:1426 msgid "Choose a block or continue typing" msgstr "" @@ -4712,9 +4651,12 @@ msgstr "" msgid "Client Information" msgstr "" +#. Label of a Link in the Build Workspace +#. Label of a shortcut in the Build Workspace #. Name of a DocType #. Label of the client_script (Code) field in DocType 'DocType Layout' #. Label of the client_script (Code) field in DocType 'Web Form' +#: core/workspace/build/build.json #: custom/doctype/client_script/client_script.json #: custom/doctype/doctype_layout/doctype_layout.json #: website/doctype/web_form/web_form.json @@ -4722,13 +4664,6 @@ msgstr "" msgid "Client Script" msgstr "" -#. Label of a Link in the Build Workspace -#. Label of a shortcut in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Client Script" -msgid "Client Script" -msgstr "" - #. Label of the client_secret (Password) field in DocType 'Connected App' #. Label of the client_secret (Password) field in DocType 'Google Settings' #. Label of the client_secret (Password) field in DocType 'Social Login Key' @@ -5055,7 +4990,6 @@ msgstr "" #. Label of a Link in the Build Workspace #: core/workspace/build/build.json -msgctxt "Communication" msgid "Communication Logs" msgstr "" @@ -5108,7 +5042,7 @@ msgstr "" msgid "Complete By" msgstr "" -#: core/doctype/user/user.py:432 templates/emails/new_user.html:10 +#: core/doctype/user/user.py:436 templates/emails/new_user.html:10 msgid "Complete Registration" msgstr "" @@ -5373,13 +5307,9 @@ msgid "Contact Us" msgstr "" #. Name of a DocType -#: website/doctype/contact_us_settings/contact_us_settings.json -msgid "Contact Us Settings" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/contact_us_settings/contact_us_settings.json #: website/workspace/website/website.json -msgctxt "Contact Us Settings" msgid "Contact Us Settings" msgstr "" @@ -5623,7 +5553,7 @@ msgstr "" #: public/js/frappe/views/file/file_view.js:112 #: public/js/frappe/views/interaction.js:18 #: public/js/frappe/views/reports/query_report.js:1188 -#: public/js/frappe/views/workspace/workspace.js:1260 +#: public/js/frappe/views/workspace/workspace.js:1258 #: workflow/page/workflow_builder/workflow_builder.js:46 msgid "Create" msgstr "" @@ -5661,7 +5591,7 @@ msgstr "" msgid "Create Custom Fields" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:968 +#: public/js/frappe/views/workspace/workspace.js:966 msgid "Create Duplicate" msgstr "" @@ -5986,14 +5916,10 @@ msgstr "" msgid "Custom Documents" msgstr "" -#. Name of a DocType -#: custom/doctype/custom_field/custom_field.json -msgid "Custom Field" -msgstr "" - #. Label of a Link in the Build Workspace +#. Name of a DocType #: core/workspace/build/build.json -msgctxt "Custom Field" +#: custom/doctype/custom_field/custom_field.json msgid "Custom Field" msgstr "" @@ -6104,7 +6030,6 @@ msgstr "" #. Label of a Link in the Build Workspace #: core/workspace/build/build.json -msgctxt "Translation" msgid "Custom Translation" msgstr "" @@ -6136,7 +6061,7 @@ msgstr "" msgid "Customization onboarding is all done!" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:554 +#: public/js/frappe/views/workspace/workspace.js:552 msgid "Customizations Discarded" msgstr "" @@ -6168,18 +6093,13 @@ msgstr "" msgid "Customize Dashboard" msgstr "" -#. Name of a DocType -#: automation/doctype/auto_repeat/auto_repeat.js:33 -#: core/doctype/doctype/doctype.js:65 -#: custom/doctype/customize_form/customize_form.json -#: public/js/frappe/views/kanban/kanban_view.js:343 -msgid "Customize Form" -msgstr "" - #. Label of a Link in the Build Workspace #. Label of a shortcut in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Customize Form" +#. Name of a DocType +#: automation/doctype/auto_repeat/auto_repeat.js:33 +#: core/doctype/doctype/doctype.js:65 core/workspace/build/build.json +#: custom/doctype/customize_form/customize_form.json +#: public/js/frappe/views/kanban/kanban_view.js:343 msgid "Customize Form" msgstr "" @@ -6302,35 +6222,27 @@ msgid "Dark Theme" msgstr "" #. Label of the dashboard (Check) field in DocType 'Role' +#. Label of a Link in the Build Workspace #. Name of a DocType #. Option for the 'Select List View' (Select) field in DocType 'Form Tour' #. Option for the 'Type' (Select) field in DocType 'Workspace Shortcut' #. Option for the 'DocType View' (Select) field in DocType 'Workspace Shortcut' #: core/doctype/role/role.json core/page/dashboard_view/dashboard_view.js:10 -#: desk/doctype/dashboard/dashboard.json desk/doctype/form_tour/form_tour.json +#: core/workspace/build/build.json desk/doctype/dashboard/dashboard.json +#: desk/doctype/form_tour/form_tour.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: public/js/frappe/ui/toolbar/search_utils.js:562 msgid "Dashboard" msgstr "" #. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Dashboard" -msgid "Dashboard" -msgstr "" - #. Name of a DocType +#: core/workspace/build/build.json #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/dashboard_chart_source/dashboard_chart_source.js:8 msgid "Dashboard Chart" msgstr "" -#. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Dashboard Chart" -msgid "Dashboard Chart" -msgstr "" - #. Name of a DocType #: desk/doctype/dashboard_chart_field/dashboard_chart_field.json msgid "Dashboard Chart Field" @@ -6805,7 +6717,7 @@ msgstr "" #: public/js/frappe/form/grid.js:63 public/js/frappe/form/toolbar.js:434 #: public/js/frappe/views/reports/report_view.js:1654 #: public/js/frappe/views/treeview.js:308 -#: public/js/frappe/views/workspace/workspace.js:866 +#: public/js/frappe/views/workspace/workspace.js:864 #: templates/discussions/reply_card.html:35 #: templates/discussions/reply_section.html:29 msgid "Delete" @@ -6847,7 +6759,7 @@ msgctxt "Title of confirmation dialog" msgid "Delete Tab" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:867 +#: public/js/frappe/views/workspace/workspace.js:865 msgid "Delete Workspace" msgstr "" @@ -6928,7 +6840,6 @@ msgstr "" #. Label of a Link in the Tools Workspace #: automation/workspace/tools/tools.json -msgctxt "Deleted Document" msgid "Deleted Documents" msgstr "" @@ -7293,7 +7204,7 @@ msgstr "" #: public/js/frappe/form/toolbar.js:316 #: public/js/frappe/views/communication.js:30 #: public/js/frappe/views/dashboard/dashboard_view.js:70 -#: public/js/frappe/views/workspace/workspace.js:545 +#: public/js/frappe/views/workspace/workspace.js:543 #: public/js/frappe/web_form/web_form.js:187 msgid "Discard" msgstr "" @@ -7436,6 +7347,8 @@ msgstr "" #. Group in Module Def's connections #. Label of the ref_doctype (Link) field in DocType 'Permission Inspector' #. Label of the ref_doctype (Link) field in DocType 'Version' +#. Label of a Link in the Build Workspace +#. Label of a shortcut in the Build Workspace #. Label of the dt (Link) field in DocType 'Client Script' #. Label of the dt (Link) field in DocType 'Custom Field' #. Option for the 'Applied On' (Select) field in DocType 'Property Setter' @@ -7452,6 +7365,7 @@ msgstr "" #: core/doctype/permission_inspector/permission_inspector.json #: core/doctype/version/version.json #: core/report/permitted_documents_for_user/permitted_documents_for_user.js:15 +#: core/workspace/build/build.json #: custom/doctype/client_script/client_script.json #: custom/doctype/custom_field/custom_field.json #: custom/doctype/property_setter/property_setter.json @@ -7465,13 +7379,6 @@ msgstr "" msgid "DocType" msgstr "" -#. Label of a Link in the Build Workspace -#. Label of a shortcut in the Build Workspace -#: core/workspace/build/build.json -msgctxt "DocType" -msgid "DocType" -msgstr "" - #: core/doctype/doctype/doctype.py:1546 msgid "DocType {0} provided for the field {1} must have atleast one Link field" msgstr "" @@ -7591,7 +7498,7 @@ msgstr "" msgid "Doctype required" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1346 +#: public/js/frappe/views/workspace/workspace.js:1344 msgid "Doctype with same route already exist. Please choose different title." msgstr "" @@ -8066,7 +7973,7 @@ msgstr "" #: public/js/frappe/views/workspace/blocks/header.js:46 #: public/js/frappe/views/workspace/blocks/paragraph.js:136 #: public/js/frappe/views/workspace/blocks/spacer.js:44 -#: public/js/frappe/views/workspace/workspace.js:608 +#: public/js/frappe/views/workspace/workspace.js:606 #: public/js/frappe/widgets/base_widget.js:33 msgid "Drag" msgstr "" @@ -8108,13 +8015,9 @@ msgid "Dropbox Refresh Token" msgstr "" #. Name of a DocType -#: integrations/doctype/dropbox_settings/dropbox_settings.json -msgid "Dropbox Settings" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/dropbox_settings/dropbox_settings.json #: integrations/workspace/integrations/integrations.json -msgctxt "Dropbox Settings" msgid "Dropbox Settings" msgstr "" @@ -8140,8 +8043,8 @@ msgstr "" #: public/js/frappe/form/grid_row_form.js:42 #: public/js/frappe/form/toolbar.js:388 -#: public/js/frappe/views/workspace/workspace.js:851 -#: public/js/frappe/views/workspace/workspace.js:1018 +#: public/js/frappe/views/workspace/workspace.js:849 +#: public/js/frappe/views/workspace/workspace.js:1016 msgid "Duplicate" msgstr "" @@ -8157,8 +8060,8 @@ msgstr "" msgid "Duplicate Name" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:590 -#: public/js/frappe/views/workspace/workspace.js:852 +#: public/js/frappe/views/workspace/workspace.js:588 +#: public/js/frappe/views/workspace/workspace.js:850 msgid "Duplicate Workspace" msgstr "" @@ -8170,7 +8073,7 @@ msgstr "" msgid "Duplicate field" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1033 +#: public/js/frappe/views/workspace/workspace.js:1031 msgid "Duplicate of {0} named as {1} is created successfully" msgstr "" @@ -8263,7 +8166,8 @@ msgstr "" #: public/js/frappe/form/toolbar.js:681 #: public/js/frappe/views/reports/query_report.js:815 #: public/js/frappe/views/reports/query_report.js:1634 -#: public/js/frappe/views/workspace/workspace.js:845 +#: public/js/frappe/views/workspace/workspace.js:95 +#: public/js/frappe/views/workspace/workspace.js:843 #: public/js/frappe/widgets/base_widget.js:64 #: public/js/frappe/widgets/chart_widget.js:299 #: public/js/frappe/widgets/number_card_widget.js:331 @@ -8401,7 +8305,7 @@ msgstr "" msgid "Edit Values" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:846 +#: public/js/frappe/views/workspace/workspace.js:844 msgid "Edit Workspace" msgstr "" @@ -8498,12 +8402,14 @@ msgstr "" msgid "Email" msgstr "" +#. Label of a Link in the Tools Workspace #. Label of the email_account (Link) field in DocType 'Communication' #. Label of the email_account (Link) field in DocType 'User Email' #. Name of a DocType #. Label of the email_account (Data) field in DocType 'Email Flag Queue' #. Label of the email_account (Link) field in DocType 'Email Queue' #. Label of the email_account (Link) field in DocType 'Unhandled Email' +#: automation/workspace/tools/tools.json #: core/doctype/communication/communication.js:199 #: core/doctype/communication/communication.json #: core/doctype/user_email/user_email.json @@ -8514,12 +8420,6 @@ msgstr "" msgid "Email Account" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Email Account" -msgid "Email Account" -msgstr "" - #: email/doctype/email_account/email_account.py:333 msgid "Email Account Disabled." msgstr "" @@ -8529,7 +8429,7 @@ msgstr "" msgid "Email Account Name" msgstr "" -#: core/doctype/user/user.py:705 +#: core/doctype/user/user.py:709 msgid "Email Account added multiple times" msgstr "" @@ -8558,14 +8458,10 @@ msgstr "" msgid "Email Addresses" msgstr "" -#. Name of a DocType -#: email/doctype/email_domain/email_domain.json -msgid "Email Domain" -msgstr "" - #. Label of a Link in the Tools Workspace +#. Name of a DocType #: automation/workspace/tools/tools.json -msgctxt "Email Domain" +#: email/doctype/email_domain/email_domain.json msgid "Email Domain" msgstr "" @@ -8580,21 +8476,17 @@ msgstr "" msgid "Email Footer Address" msgstr "" +#. Label of a Link in the Tools Workspace #. Name of a DocType #. Label of the email_group (Link) field in DocType 'Email Group Member' #. Label of the email_group (Link) field in DocType 'Newsletter Email Group' +#: automation/workspace/tools/tools.json #: email/doctype/email_group/email_group.json #: email/doctype/email_group_member/email_group_member.json #: email/doctype/newsletter_email_group/newsletter_email_group.json msgid "Email Group" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Email Group" -msgid "Email Group" -msgstr "" - #. Name of a DocType #: email/doctype/email_group_member/email_group_member.json msgid "Email Group Member" @@ -8699,20 +8591,16 @@ msgstr "" msgid "Email Sync Option" msgstr "" +#. Label of a Link in the Tools Workspace #. Label of the email_template (Link) field in DocType 'Communication' #. Name of a DocType +#: automation/workspace/tools/tools.json #: core/doctype/communication/communication.json #: email/doctype/email_template/email_template.json #: public/js/frappe/views/communication.js:95 msgid "Email Template" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Email Template" -msgid "Email Template" -msgstr "" - #. Label of the enable_email_threads_on_assigned_document (Check) field in #. DocType 'Notification Settings' #: desk/doctype/notification_settings/notification_settings.json @@ -9231,7 +9119,6 @@ msgstr "" #. Label of a Link in the Build Workspace #: core/workspace/build/build.json -msgctxt "Error Log" msgid "Error Logs" msgstr "" @@ -9537,13 +9424,9 @@ msgstr "" msgid "Export Customizations" msgstr "" -#: public/js/frappe/data_import/data_exporter.js:14 -msgid "Export Data" -msgstr "" - #. Label of a Link in the Tools Workspace #: automation/workspace/tools/tools.json -msgctxt "Data Export" +#: public/js/frappe/data_import/data_exporter.js:14 msgid "Export Data" msgstr "" @@ -9760,7 +9643,7 @@ msgstr "" msgid "Failed to render subject: {}" msgstr "" -#: email/doctype/email_queue/email_queue.py:294 +#: email/doctype/email_queue/email_queue.py:301 msgid "Failed to send email with subject:" msgstr "" @@ -10080,15 +9963,11 @@ msgstr "" msgid "Fieldtype cannot be changed from {0} to {1} in row {2}" msgstr "" +#. Label of a shortcut in the Tools Workspace #. Name of a DocType #. Option for the 'Select List View' (Select) field in DocType 'Form Tour' -#: core/doctype/file/file.json desk/doctype/form_tour/form_tour.json -msgid "File" -msgstr "" - -#. Label of a shortcut in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "File" +#: automation/workspace/tools/tools.json core/doctype/file/file.json +#: desk/doctype/form_tour/form_tour.json msgid "File" msgstr "" @@ -10176,14 +10055,10 @@ msgstr "" msgid "File {0} does not exist" msgstr "" -#. Label of the files_tab (Tab Break) field in DocType 'System Settings' -#: core/doctype/system_settings/system_settings.json -msgid "Files" -msgstr "" - #. Label of a Link in the Tools Workspace +#. Label of the files_tab (Tab Break) field in DocType 'System Settings' #: automation/workspace/tools/tools.json -msgctxt "File" +#: core/doctype/system_settings/system_settings.json msgid "Files" msgstr "" @@ -10828,7 +10703,7 @@ msgid "Frappe Light" msgstr "" #. Option for the 'Service' (Select) field in DocType 'Email Account' -#: email/doctype/email_account/email_account.json email/frappemail.py:91 +#: email/doctype/email_account/email_account.json msgid "Frappe Mail" msgstr "" @@ -11233,14 +11108,10 @@ msgstr "" #. Label of the google_calendar (Link) field in DocType 'Event' #. Name of a DocType #. Label of the sb_00 (Section Break) field in DocType 'Google Calendar' +#. Label of a Link in the Integrations Workspace #: desk/doctype/event/event.json #: integrations/doctype/google_calendar/google_calendar.json -msgid "Google Calendar" -msgstr "" - -#. Label of a Link in the Integrations Workspace #: integrations/workspace/integrations/integrations.json -msgctxt "Google Calendar" msgid "Google Calendar" msgstr "" @@ -11292,14 +11163,10 @@ msgstr "" #. Label of the google_contacts (Link) field in DocType 'Contact' #. Name of a DocType #. Label of the sb_00 (Section Break) field in DocType 'Google Contacts' +#. Label of a Link in the Integrations Workspace #: contacts/doctype/contact/contact.json #: integrations/doctype/google_contacts/google_contacts.json -msgid "Google Contacts" -msgstr "" - -#. Label of a Link in the Integrations Workspace #: integrations/workspace/integrations/integrations.json -msgctxt "Google Contacts" msgid "Google Contacts" msgstr "" @@ -11319,14 +11186,10 @@ msgstr "" #. Name of a DocType #. Label of the google_drive_section (Section Break) field in DocType 'Google #. Drive' -#: integrations/doctype/google_drive/google_drive.json -#: public/js/frappe/file_uploader/FileUploader.vue:164 -msgid "Google Drive" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/google_drive/google_drive.json #: integrations/workspace/integrations/integrations.json -msgctxt "Google Drive" +#: public/js/frappe/file_uploader/FileUploader.vue:164 msgid "Google Drive" msgstr "" @@ -11377,13 +11240,9 @@ msgid "Google Services" msgstr "" #. Name of a DocType -#: integrations/doctype/google_settings/google_settings.json -msgid "Google Settings" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/google_settings/google_settings.json #: integrations/workspace/integrations/integrations.json -msgctxt "Google Settings" msgid "Google Settings" msgstr "" @@ -11683,13 +11542,9 @@ msgid "Help" msgstr "" #. Name of a DocType -#: website/doctype/help_article/help_article.json -msgid "Help Article" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/help_article/help_article.json #: website/workspace/website/website.json -msgctxt "Help Article" msgid "Help Article" msgstr "" @@ -11699,13 +11554,9 @@ msgid "Help Articles" msgstr "" #. Name of a DocType -#: website/doctype/help_category/help_category.json -msgid "Help Category" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/help_category/help_category.json #: website/workspace/website/website.json -msgctxt "Help Category" msgid "Help Category" msgstr "" @@ -11782,7 +11633,7 @@ msgstr "" #. Option for the 'Page Number' (Select) field in DocType 'Print Format' #: printing/doctype/print_format/print_format.json -#: public/js/frappe/views/workspace/workspace.js:857 +#: public/js/frappe/views/workspace/workspace.js:855 #: public/js/frappe/widgets/base_widget.js:46 #: public/js/frappe/widgets/base_widget.js:178 #: public/js/print_format_builder/PrintFormatControls.vue:243 @@ -11891,7 +11742,7 @@ msgstr "" msgid "Hide Weekends" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:858 +#: public/js/frappe/views/workspace/workspace.js:856 msgid "Hide Workspace" msgstr "" @@ -12073,9 +11924,9 @@ msgstr "" #: desk/doctype/workspace_link/workspace_link.json #: desk/doctype/workspace_shortcut/workspace_shortcut.json #: integrations/doctype/social_login_key/social_login_key.json -#: public/js/frappe/views/workspace/workspace.js:675 -#: public/js/frappe/views/workspace/workspace.js:1003 -#: public/js/frappe/views/workspace/workspace.js:1248 +#: public/js/frappe/views/workspace/workspace.js:673 +#: public/js/frappe/views/workspace/workspace.js:1001 +#: public/js/frappe/views/workspace/workspace.js:1246 #: workflow/doctype/workflow_state/workflow_state.json msgid "Icon" msgstr "" @@ -12432,7 +12283,7 @@ msgstr "" msgid "Impersonate as {0}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:233 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:246 msgid "Impersonated by {0}" msgstr "" @@ -12465,7 +12316,6 @@ msgstr "" #. Label of a Link in the Tools Workspace #. Label of a shortcut in the Tools Workspace #: automation/workspace/tools/tools.json -msgctxt "Data Import" msgid "Import Data" msgstr "" @@ -12812,9 +12662,9 @@ msgstr "" msgid "Indicator Color" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:682 -#: public/js/frappe/views/workspace/workspace.js:1010 -#: public/js/frappe/views/workspace/workspace.js:1254 +#: public/js/frappe/views/workspace/workspace.js:680 +#: public/js/frappe/views/workspace/workspace.js:1008 +#: public/js/frappe/views/workspace/workspace.js:1252 msgid "Indicator color" msgstr "" @@ -13150,7 +13000,7 @@ msgstr "" msgid "Invalid Parameters." msgstr "" -#: core/doctype/user/user.py:1191 www/update-password.html:121 +#: core/doctype/user/user.py:1195 www/update-password.html:121 #: www/update-password.html:142 www/update-password.html:144 #: www/update-password.html:245 msgid "Invalid Password" @@ -13850,13 +13700,9 @@ msgid "LDAP Server Url" msgstr "" #. Name of a DocType -#: integrations/doctype/ldap_settings/ldap_settings.json -msgid "LDAP Settings" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/ldap_settings/ldap_settings.json #: integrations/workspace/integrations/integrations.json -msgctxt "LDAP Settings" msgid "LDAP Settings" msgstr "" @@ -15507,13 +15353,9 @@ msgid "Middle Name" msgstr "" #. Name of a DocType -#: automation/doctype/milestone/milestone.json -msgid "Milestone" -msgstr "" - #. Label of a Link in the Tools Workspace +#: automation/doctype/milestone/milestone.json #: automation/workspace/tools/tools.json -msgctxt "Milestone" msgid "Milestone" msgstr "" @@ -15658,13 +15500,8 @@ msgid "Module (for export)" msgstr "" #. Name of a DocType -#: core/doctype/module_def/module_def.json -msgid "Module Def" -msgstr "" - #. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Module Def" +#: core/doctype/module_def/module_def.json core/workspace/build/build.json msgid "Module Def" msgstr "" @@ -15680,26 +15517,18 @@ msgstr "" msgid "Module Name" msgstr "" -#. Name of a DocType -#: desk/doctype/module_onboarding/module_onboarding.json -msgid "Module Onboarding" -msgstr "" - #. Label of a Link in the Build Workspace +#. Name of a DocType #: core/workspace/build/build.json -msgctxt "Module Onboarding" +#: desk/doctype/module_onboarding/module_onboarding.json msgid "Module Onboarding" msgstr "" #. Name of a DocType #. Label of the module_profile (Link) field in DocType 'User' -#: core/doctype/module_profile/module_profile.json core/doctype/user/user.json -msgid "Module Profile" -msgstr "" - #. Label of a Link in the Users Workspace +#: core/doctype/module_profile/module_profile.json core/doctype/user/user.json #: core/workspace/users/users.json -msgctxt "Module Profile" msgid "Module Profile" msgstr "" @@ -16075,13 +15904,9 @@ msgid "Navbar Item" msgstr "" #. Name of a DocType -#: core/doctype/navbar_settings/navbar_settings.json -msgid "Navbar Settings" -msgstr "" - #. Label of a Link in the Build Workspace +#: core/doctype/navbar_settings/navbar_settings.json #: core/workspace/build/build.json -msgctxt "Navbar Settings" msgid "Navbar Settings" msgstr "" @@ -16153,6 +15978,7 @@ msgstr "" #: email/doctype/notification/notification.json #: public/js/frappe/form/success_action.js:77 #: public/js/frappe/views/treeview.js:450 +#: public/js/frappe/views/workspace/workspace.js:95 #: social/doctype/energy_point_rule/energy_point_rule.json #: website/doctype/web_form/templates/web_list.html:15 www/list.html:19 msgid "New" @@ -16286,7 +16112,7 @@ msgstr "" msgid "New Workflow Name" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1215 +#: public/js/frappe/views/workspace/workspace.js:1213 msgid "New Workspace" msgstr "" @@ -16344,23 +16170,18 @@ msgstr "" msgid "New {} releases for the following apps are available" msgstr "" -#: core/doctype/user/user.py:768 +#: core/doctype/user/user.py:772 msgid "Newly created user {0} has no roles enabled." msgstr "" #. Label of a Card Break in the Tools Workspace +#. Label of a Link in the Tools Workspace #. Name of a DocType #: automation/workspace/tools/tools.json #: email/doctype/newsletter/newsletter.json msgid "Newsletter" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Newsletter" -msgid "Newsletter" -msgstr "" - #. Name of a DocType #: email/doctype/newsletter_attachment/newsletter_attachment.json msgid "Newsletter Attachment" @@ -16632,7 +16453,7 @@ msgstr "" msgid "No Results found" msgstr "" -#: core/doctype/user/user.py:769 +#: core/doctype/user/user.py:773 msgid "No Roles Specified" msgstr "" @@ -16680,7 +16501,7 @@ msgstr "" msgid "No changes made because old and new name are the same." msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1520 +#: public/js/frappe/views/workspace/workspace.js:1518 msgid "No changes made on the page" msgstr "" @@ -16886,7 +16707,7 @@ msgstr "" msgid "Normalized Query" msgstr "" -#: core/doctype/user/user.py:974 templates/includes/login/login.js:257 +#: core/doctype/user/user.py:978 templates/includes/login/login.js:257 #: utils/oauth.py:265 msgid "Not Allowed" msgstr "" @@ -17050,15 +16871,10 @@ msgstr "" msgid "Not permitted to view {0}" msgstr "" +#. Label of a Link in the Tools Workspace #. Name of a DocType #: automation/doctype/auto_repeat/auto_repeat.py:396 -#: desk/doctype/note/note.json -msgid "Note" -msgstr "" - -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Note" +#: automation/workspace/tools/tools.json desk/doctype/note/note.json msgid "Note" msgstr "" @@ -17137,12 +16953,14 @@ msgid "Nothing to update" msgstr "" #. Label of the notification (Section Break) field in DocType 'Auto Repeat' +#. Label of a Link in the Tools Workspace #. Option for the 'Communication Type' (Select) field in DocType #. 'Communication' #. Name of a DocType #. Label of the notification_section (Section Break) field in DocType 'S3 #. Backup Settings' #: automation/doctype/auto_repeat/auto_repeat.json +#: automation/workspace/tools/tools.json #: core/doctype/communication/communication.json #: core/doctype/communication/mixins.py:142 #: email/doctype/notification/notification.json @@ -17150,12 +16968,6 @@ msgstr "" msgid "Notification" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Notification" -msgid "Notification" -msgstr "" - #. Name of a DocType #: desk/doctype/notification_log/notification_log.json msgid "Notification Log" @@ -17166,18 +16978,14 @@ msgstr "" msgid "Notification Recipient" msgstr "" +#. Label of a Link in the Tools Workspace #. Name of a DocType +#: automation/workspace/tools/tools.json #: desk/doctype/notification_settings/notification_settings.json #: public/js/frappe/ui/notifications/notifications.js:37 msgid "Notification Settings" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Notification Settings" -msgid "Notification Settings" -msgstr "" - #. Name of a DocType #: desk/doctype/notification_subscribed_document/notification_subscribed_document.json msgid "Notification Subscribed Document" @@ -17363,13 +17171,9 @@ msgid "OAuth Bearer Token" msgstr "" #. Name of a DocType -#: integrations/doctype/oauth_client/oauth_client.json -msgid "OAuth Client" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/oauth_client/oauth_client.json #: integrations/workspace/integrations/integrations.json -msgctxt "OAuth Client" msgid "OAuth Client" msgstr "" @@ -17388,13 +17192,9 @@ msgid "OAuth Error" msgstr "" #. Name of a DocType -#: integrations/doctype/oauth_provider_settings/oauth_provider_settings.json -msgid "OAuth Provider Settings" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/oauth_provider_settings/oauth_provider_settings.json #: integrations/workspace/integrations/integrations.json -msgctxt "OAuth Provider Settings" msgid "OAuth Provider Settings" msgstr "" @@ -17599,7 +17399,7 @@ msgstr "" msgid "One of" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1355 +#: public/js/frappe/views/workspace/workspace.js:1353 msgid "One of the child page with name {0} already exist in {1} Section. Please update the name of the child page first before moving" msgstr "" @@ -17641,7 +17441,7 @@ msgstr "" msgid "Only Workspace Manager can edit public workspaces" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:579 +#: public/js/frappe/views/workspace/workspace.js:577 msgid "Only Workspace Manager can sort or edit this page" msgstr "" @@ -18082,25 +17882,17 @@ msgstr "" #. Label of the package (Link) field in DocType 'Module Def' #. Name of a DocType #. Label of the package (Link) field in DocType 'Package Release' -#: core/doctype/module_def/module_def.json core/doctype/package/package.json -#: core/doctype/package_release/package_release.json www/attribution.html:34 -msgid "Package" -msgstr "" - #. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Package" +#: core/doctype/module_def/module_def.json core/doctype/package/package.json +#: core/doctype/package_release/package_release.json +#: core/workspace/build/build.json www/attribution.html:34 msgid "Package" msgstr "" #. Name of a DocType -#: core/doctype/package_import/package_import.json -msgid "Package Import" -msgstr "" - #. Label of a Link in the Build Workspace +#: core/doctype/package_import/package_import.json #: core/workspace/build/build.json -msgctxt "Package Import" msgid "Package Import" msgstr "" @@ -18187,7 +17979,7 @@ msgstr "" msgid "Page Route" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1542 +#: public/js/frappe/views/workspace/workspace.js:1540 msgid "Page Saved Successfully" msgstr "" @@ -18232,7 +18024,7 @@ msgstr "" msgid "Page to show on the website\n" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1342 +#: public/js/frappe/views/workspace/workspace.js:1340 msgid "Page with title {0} already exist." msgstr "" @@ -18249,9 +18041,9 @@ msgid "Parameter" msgstr "" #: public/js/frappe/model/model.js:142 -#: public/js/frappe/views/workspace/workspace.js:649 -#: public/js/frappe/views/workspace/workspace.js:977 -#: public/js/frappe/views/workspace/workspace.js:1224 +#: public/js/frappe/views/workspace/workspace.js:647 +#: public/js/frappe/views/workspace/workspace.js:975 +#: public/js/frappe/views/workspace/workspace.js:1222 msgid "Parent" msgstr "" @@ -18375,11 +18167,11 @@ msgstr "" msgid "Password" msgstr "" -#: core/doctype/user/user.py:1037 +#: core/doctype/user/user.py:1041 msgid "Password Email Sent" msgstr "" -#: core/doctype/user/user.py:412 +#: core/doctype/user/user.py:416 msgid "Password Reset" msgstr "" @@ -18413,7 +18205,7 @@ msgstr "" msgid "Password not found for {0} {1} {2}" msgstr "" -#: core/doctype/user/user.py:1036 +#: core/doctype/user/user.py:1040 msgid "Password reset instructions have been sent to {}'s email" msgstr "" @@ -18425,7 +18217,7 @@ msgstr "" msgid "Password size exceeded the maximum allowed size" msgstr "" -#: core/doctype/user/user.py:832 +#: core/doctype/user/user.py:836 msgid "Password size exceeded the maximum allowed size." msgstr "" @@ -18790,7 +18582,7 @@ msgstr "" msgid "Please add a valid comment." msgstr "" -#: core/doctype/user/user.py:1019 +#: core/doctype/user/user.py:1023 msgid "Please ask your administrator to verify your sign-up" msgstr "" @@ -18822,7 +18614,7 @@ msgstr "" msgid "Please check the value of \"Fetch From\" set for field {0}" msgstr "" -#: core/doctype/user/user.py:1017 +#: core/doctype/user/user.py:1021 msgid "Please check your email for verification" msgstr "" @@ -19113,7 +18905,7 @@ msgstr "" msgid "Please setup default Email Account from Settings > Email Account" msgstr "" -#: core/doctype/user/user.py:377 +#: core/doctype/user/user.py:381 msgid "Please setup default outgoing Email Account from Settings > Email Account" msgstr "" @@ -19216,13 +19008,9 @@ msgid "Portal Menu Item" msgstr "" #. Name of a DocType -#: website/doctype/portal_settings/portal_settings.json -msgid "Portal Settings" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/portal_settings/portal_settings.json #: website/workspace/website/website.json -msgctxt "Portal Settings" msgid "Portal Settings" msgstr "" @@ -19490,11 +19278,12 @@ msgid "Print Documents" msgstr "" #. Label of the print_format (Link) field in DocType 'Auto Repeat' +#. Label of a Link in the Build Workspace #. Label of the print_format (Link) field in DocType 'Notification' #. Name of a DocType #. Label of the print_format (Link) field in DocType 'Web Form' #: automation/doctype/auto_repeat/auto_repeat.json -#: email/doctype/notification/notification.json +#: core/workspace/build/build.json email/doctype/notification/notification.json #: printing/doctype/print_format/print_format.json #: printing/page/print/print.js:94 printing/page/print/print.js:819 #: public/js/frappe/list/bulk_operations.js:59 @@ -19502,12 +19291,6 @@ msgstr "" msgid "Print Format" msgstr "" -#. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Print Format" -msgid "Print Format" -msgstr "" - #. Label of a Link in the Tools Workspace #. Label of a shortcut in the Build Workspace #. Label of the print_format_builder (Check) field in DocType 'Print Format' @@ -19558,15 +19341,11 @@ msgstr "" msgid "Print Formats allow you can define looks for documents when printed or converted to PDF. You can also create a custom Print Format using drag-and-drop tools." msgstr "" +#. Label of a Link in the Tools Workspace #. Name of a DocType #. Label of the print_heading (Data) field in DocType 'Print Heading' -#: printing/doctype/print_heading/print_heading.json -msgid "Print Heading" -msgstr "" - -#. Label of a Link in the Tools Workspace #: automation/workspace/tools/tools.json -msgctxt "Print Heading" +#: printing/doctype/print_heading/print_heading.json msgid "Print Heading" msgstr "" @@ -19603,8 +19382,10 @@ msgstr "" msgid "Print Server" msgstr "" +#. Label of a Link in the Tools Workspace #. Label of the column_break_25 (Section Break) field in DocType 'Notification' #. Name of a DocType +#: automation/workspace/tools/tools.json #: email/doctype/notification/notification.json #: printing/doctype/print_settings/print_settings.json #: printing/doctype/print_style/print_style.js:6 @@ -19613,12 +19394,6 @@ msgstr "" msgid "Print Settings" msgstr "" -#. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "Print Settings" -msgid "Print Settings" -msgstr "" - #. Label of the print_style_section (Section Break) field in DocType 'Print #. Settings' #. Label of the print_style (Link) field in DocType 'Print Settings' @@ -19741,7 +19516,7 @@ msgstr "" msgid "Processing" msgstr "" -#: email/doctype/email_queue/email_queue.py:447 +#: email/doctype/email_queue/email_queue.py:454 msgid "Processing..." msgstr "" @@ -19816,9 +19591,9 @@ msgstr "" #: desk/doctype/event/event.json desk/doctype/note/note.json #: desk/doctype/note/note_list.js:6 desk/doctype/workspace/workspace.json #: public/js/frappe/views/interaction.js:78 -#: public/js/frappe/views/workspace/workspace.js:656 -#: public/js/frappe/views/workspace/workspace.js:984 -#: public/js/frappe/views/workspace/workspace.js:1230 +#: public/js/frappe/views/workspace/workspace.js:654 +#: public/js/frappe/views/workspace/workspace.js:982 +#: public/js/frappe/views/workspace/workspace.js:1228 msgid "Public" msgstr "" @@ -19927,13 +19702,9 @@ msgid "Purple" msgstr "" #. Name of a DocType -#: integrations/doctype/push_notification_settings/push_notification_settings.json -msgid "Push Notification Settings" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/push_notification_settings/push_notification_settings.json #: integrations/workspace/integrations/integrations.json -msgctxt "Push Notification Settings" msgid "Push Notification Settings" msgstr "" @@ -20736,7 +20507,7 @@ msgstr "" msgid "Refreshing..." msgstr "" -#: core/doctype/user/user.py:981 +#: core/doctype/user/user.py:985 msgid "Registered but disabled" msgstr "" @@ -21001,6 +20772,8 @@ msgstr "" #. Page and Report' #. Label of the report (Link) field in DocType 'Role Permission for Page and #. Report' +#. Label of a Link in the Build Workspace +#. Label of a shortcut in the Build Workspace #. Option for the 'Chart Type' (Select) field in DocType 'Dashboard Chart' #. Option for the 'Select List View' (Select) field in DocType 'Form Tour' #. Option for the 'Type' (Select) field in DocType 'Number Card' @@ -21013,6 +20786,7 @@ msgstr "" #: core/doctype/custom_role/custom_role.json core/doctype/docperm/docperm.json #: core/doctype/report/report.json #: core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.json +#: core/workspace/build/build.json #: desk/doctype/dashboard_chart/dashboard_chart.json #: desk/doctype/form_tour/form_tour.json #: desk/doctype/number_card/number_card.json @@ -21024,13 +20798,6 @@ msgstr "" msgid "Report" msgstr "" -#. Label of a Link in the Build Workspace -#. Label of a shortcut in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Report" -msgid "Report" -msgstr "" - #. Option for the 'Report Type' (Select) field in DocType 'Report' #. Option for the 'DocType View' (Select) field in DocType 'Workspace Shortcut' #: core/doctype/report/report.json @@ -21601,6 +21368,8 @@ msgstr "" #. Label of the role (Link) field in DocType 'Has Role' #. Name of a DocType #. Label of the role (Link) field in DocType 'User Type' +#. Label of a Link in the Users Workspace +#. Label of a shortcut in the Users Workspace #. Label of the role (Link) field in DocType 'Onboarding Permission' #. Label of the role (Link) field in DocType 'ToDo' #. Label of the role (Link) field in DocType 'OAuth Client Role' @@ -21614,6 +21383,7 @@ msgstr "" #: core/doctype/user_type/user_type.py:109 #: core/page/permission_manager/permission_manager.js:212 #: core/page/permission_manager/permission_manager.js:450 +#: core/workspace/users/users.json #: desk/doctype/onboarding_permission/onboarding_permission.json #: desk/doctype/todo/todo.json #: integrations/doctype/oauth_client_role/oauth_client_role.json @@ -21623,13 +21393,6 @@ msgstr "" msgid "Role" msgstr "" -#. Label of a Link in the Users Workspace -#. Label of a shortcut in the Users Workspace -#: core/workspace/users/users.json -msgctxt "Role" -msgid "Role" -msgstr "" - #: core/doctype/role/role.js:8 msgid "Role 'All' will be given to all system + website users." msgstr "" @@ -21645,13 +21408,9 @@ msgid "Role Name" msgstr "" #. Name of a DocType -#: core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.json -msgid "Role Permission for Page and Report" -msgstr "" - #. Label of a Link in the Users Workspace +#: core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.json #: core/workspace/users/users.json -msgctxt "Role Permission for Page and Report" msgid "Role Permission for Page and Report" msgstr "" @@ -21676,14 +21435,10 @@ msgstr "" #. Name of a DocType #. Label of the role_profile_name (Link) field in DocType 'User' #. Label of the role_profile (Link) field in DocType 'User Role Profile' +#. Label of a Link in the Users Workspace #: core/doctype/role_profile/role_profile.json core/doctype/user/user.json #: core/doctype/user_role_profile/user_role_profile.json -msgid "Role Profile" -msgstr "" - -#. Label of a Link in the Users Workspace #: core/workspace/users/users.json -msgctxt "Role Profile" msgid "Role Profile" msgstr "" @@ -21937,13 +21692,9 @@ msgid "Run scheduled jobs only if checked" msgstr "" #. Name of a DocType -#: integrations/doctype/s3_backup_settings/s3_backup_settings.json -msgid "S3 Backup Settings" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/s3_backup_settings/s3_backup_settings.json #: integrations/workspace/integrations/integrations.json -msgctxt "S3 Backup Settings" msgid "S3 Backup Settings" msgstr "" @@ -21983,13 +21734,9 @@ msgid "SMS Parameter" msgstr "" #. Name of a DocType -#: core/doctype/sms_settings/sms_settings.json -msgid "SMS Settings" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: core/doctype/sms_settings/sms_settings.json #: integrations/workspace/integrations/integrations.json -msgctxt "SMS Settings" msgid "SMS Settings" msgstr "" @@ -22111,7 +21858,7 @@ msgstr "" #: public/js/frappe/views/kanban/kanban_view.js:343 #: public/js/frappe/views/reports/query_report.js:1802 #: public/js/frappe/views/reports/report_view.js:1640 -#: public/js/frappe/views/workspace/workspace.js:530 +#: public/js/frappe/views/workspace/workspace.js:528 #: public/js/frappe/widgets/base_widget.js:142 #: public/js/frappe/widgets/quick_list_widget.js:119 #: public/js/print_format_builder/print_format_builder.bundle.js:15 @@ -22166,7 +21913,7 @@ msgstr "" #: public/js/frappe/list/list_settings.js:40 #: public/js/frappe/views/kanban/kanban_settings.js:47 -#: public/js/frappe/views/workspace/workspace.js:542 +#: public/js/frappe/views/workspace/workspace.js:540 msgid "Saving" msgstr "" @@ -22237,22 +21984,17 @@ msgid "Scheduled Job Log" msgstr "" #. Name of a DocType +#. Label of a Link in the Build Workspace #. Label of the scheduled_job_type (Link) field in DocType 'System Health #. Report Failing Jobs' #: core/doctype/scheduled_job_type/scheduled_job_type.json +#: core/workspace/build/build.json #: desk/doctype/system_health_report_failing_jobs/system_health_report_failing_jobs.json msgid "Scheduled Job Type" msgstr "" #. Label of a Link in the Build Workspace #: core/workspace/build/build.json -msgctxt "Scheduled Job Type" -msgid "Scheduled Job Type" -msgstr "" - -#. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Scheduled Job Log" msgid "Scheduled Jobs Logs" msgstr "" @@ -23202,15 +22944,11 @@ msgstr "" #. Label of the server_script (Link) field in DocType 'Scheduled Job Type' #. Name of a DocType -#: core/doctype/scheduled_job_type/scheduled_job_type.json -#: core/doctype/server_script/server_script.json -msgid "Server Script" -msgstr "" - #. Label of a Link in the Build Workspace #. Label of a shortcut in the Build Workspace +#: core/doctype/scheduled_job_type/scheduled_job_type.json +#: core/doctype/server_script/server_script.json #: core/workspace/build/build.json -msgctxt "Server Script" msgid "Server Script" msgstr "" @@ -23480,7 +23218,7 @@ msgstr "" #: integrations/workspace/integrations/integrations.json #: public/js/frappe/form/templates/print_layout.html:25 #: public/js/frappe/ui/toolbar/toolbar.js:289 -#: public/js/frappe/views/workspace/workspace.js:558 +#: public/js/frappe/views/workspace/workspace.js:556 #: website/doctype/web_form/web_form.json #: website/doctype/web_page/web_page.json msgid "Settings" @@ -23886,6 +23624,11 @@ msgstr "" msgid "Show more details" msgstr "" +#. Label of the show_on_timeline (Check) field in DocType 'DocField' +#: core/doctype/docfield/docfield.json +msgid "Show on Timeline" +msgstr "" + #. Description of the 'Stats Time Interval' (Select) field in DocType 'Number #. Card' #: desk/doctype/number_card/number_card.json @@ -23936,7 +23679,7 @@ msgstr "" msgid "Sign Up and Confirmation" msgstr "" -#: core/doctype/user/user.py:974 +#: core/doctype/user/user.py:978 msgid "Sign Up is disabled" msgstr "" @@ -24080,13 +23823,9 @@ msgid "Slack Webhook Error" msgstr "" #. Name of a DocType -#: integrations/doctype/slack_webhook_url/slack_webhook_url.json -msgid "Slack Webhook URL" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/slack_webhook_url/slack_webhook_url.json #: integrations/workspace/integrations/integrations.json -msgctxt "Slack Webhook URL" msgid "Slack Webhook URL" msgstr "" @@ -24152,13 +23891,9 @@ msgid "Social Link Type" msgstr "" #. Name of a DocType -#: integrations/doctype/social_login_key/social_login_key.json -msgid "Social Login Key" -msgstr "" - #. Label of a Link in the Integrations Workspace +#: integrations/doctype/social_login_key/social_login_key.json #: integrations/workspace/integrations/integrations.json -msgctxt "Social Login Key" msgid "Social Login Key" msgstr "" @@ -24958,7 +24693,7 @@ msgstr "" msgid "Suggested Indexes" msgstr "" -#: core/doctype/user/user.py:689 +#: core/doctype/user/user.py:693 msgid "Suggested Username: {0}" msgstr "" @@ -25283,13 +25018,9 @@ msgid "System Page" msgstr "" #. Name of a DocType -#: core/doctype/system_settings/system_settings.json -msgid "System Settings" -msgstr "" - #. Label of a shortcut in the Build Workspace +#: core/doctype/system_settings/system_settings.json #: core/workspace/build/build.json -msgctxt "System Settings" msgid "System Settings" msgstr "" @@ -25485,7 +25216,7 @@ msgstr "" msgid "Templates" msgstr "" -#: core/doctype/user/user.py:985 +#: core/doctype/user/user.py:989 msgid "Temporarily Disabled" msgstr "" @@ -25745,11 +25476,11 @@ msgid "" "" msgstr "" -#: core/doctype/user/user.py:945 +#: core/doctype/user/user.py:949 msgid "The reset password link has been expired" msgstr "" -#: core/doctype/user/user.py:947 +#: core/doctype/user/user.py:951 msgid "The reset password link has either been used before or is invalid" msgstr "" @@ -26181,7 +25912,7 @@ msgstr "" msgid "This will terminate the job immediately and might be dangerous, are you sure? " msgstr "" -#: core/doctype/user/user.py:1205 +#: core/doctype/user/user.py:1209 msgid "Throttled" msgstr "" @@ -26395,9 +26126,9 @@ msgstr "" #: desk/doctype/system_health_report_errors/system_health_report_errors.json #: desk/doctype/workspace/workspace.json #: email/doctype/email_group/email_group.json -#: public/js/frappe/views/workspace/workspace.js:642 -#: public/js/frappe/views/workspace/workspace.js:971 -#: public/js/frappe/views/workspace/workspace.js:1218 +#: public/js/frappe/views/workspace/workspace.js:640 +#: public/js/frappe/views/workspace/workspace.js:969 +#: public/js/frappe/views/workspace/workspace.js:1216 #: website/doctype/blog_category/blog_category.json #: website/doctype/blog_post/blog_post.json #: website/doctype/blog_settings/blog_settings.json @@ -26451,13 +26182,8 @@ msgstr "" msgid "To Date Field" msgstr "" -#: desk/doctype/todo/todo_list.js:6 -msgid "To Do" -msgstr "" - #. Label of a Link in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "ToDo" +#: automation/workspace/tools/tools.json desk/doctype/todo/todo_list.js:6 msgid "To Do" msgstr "" @@ -26568,15 +26294,11 @@ msgstr "" msgid "To version" msgstr "" +#. Label of a shortcut in the Tools Workspace #. Name of a DocType #. Name of a report -#: desk/doctype/todo/todo.json desk/report/todo/todo.json -msgid "ToDo" -msgstr "" - -#. Label of a shortcut in the Tools Workspace -#: automation/workspace/tools/tools.json -msgctxt "ToDo" +#: automation/workspace/tools/tools.json desk/doctype/todo/todo.json +#: desk/report/todo/todo.json msgid "ToDo" msgstr "" @@ -26651,7 +26373,7 @@ msgstr "" msgid "Too many changes to database in single action." msgstr "" -#: core/doctype/user/user.py:986 +#: core/doctype/user/user.py:990 msgid "Too many users signed up recently, so the registration is disabled. Please try back in an hour" msgstr "" @@ -27220,7 +26942,7 @@ msgstr "" msgid "Unhandled Emails" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:599 +#: public/js/frappe/views/workspace/workspace.js:597 msgid "Unhide Workspace" msgstr "" @@ -27342,7 +27064,7 @@ msgstr "" #: printing/page/print_format_builder/print_format_builder.js:670 #: printing/page/print_format_builder/print_format_builder.js:757 #: public/js/frappe/form/grid_row.js:404 -#: public/js/frappe/views/workspace/workspace.js:690 +#: public/js/frappe/views/workspace/workspace.js:688 msgid "Update" msgstr "" @@ -27352,7 +27074,7 @@ msgstr "" msgid "Update Amendment Naming" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:639 +#: public/js/frappe/views/workspace/workspace.js:637 msgid "Update Details" msgstr "" @@ -27447,7 +27169,7 @@ msgctxt "Freeze message while updating a document" msgid "Updating" msgstr "" -#: email/doctype/email_queue/email_queue.py:446 +#: email/doctype/email_queue/email_queue.py:453 msgid "Updating Email Queue Statuses. The emails will be picked up in the next scheduled run." msgstr "" @@ -27620,6 +27342,8 @@ msgstr "" #. Name of a DocType #. Label of the user (Link) field in DocType 'User Group Member' #. Label of the user (Link) field in DocType 'User Permission' +#. Label of a Link in the Users Workspace +#. Label of a shortcut in the Users Workspace #. Label of the user (Link) field in DocType 'Dashboard Settings' #. Label of the user (Link) field in DocType 'Note Seen By' #. Label of the user (Link) field in DocType 'Notification Settings' @@ -27646,6 +27370,7 @@ msgstr "" #: core/doctype/user_group_member/user_group_member.json #: core/doctype/user_permission/user_permission.json #: core/report/permitted_documents_for_user/permitted_documents_for_user.js:8 +#: core/workspace/users/users.json #: desk/doctype/dashboard_settings/dashboard_settings.json #: desk/doctype/note_seen_by/note_seen_by.json #: desk/doctype/notification_settings/notification_settings.json @@ -27667,13 +27392,6 @@ msgstr "" msgid "User" msgstr "" -#. Label of a Link in the Users Workspace -#. Label of a shortcut in the Users Workspace -#: core/workspace/users/users.json -msgctxt "User" -msgid "User" -msgstr "" - #. Label of the user (Link) field in DocType 'Access Log' #: core/doctype/access_log/access_log.json msgid "User " @@ -27811,7 +27529,9 @@ msgstr "" msgid "User Permission" msgstr "" +#. Label of a Link in the Users Workspace #: core/page/permission_manager/permission_manager_help.html:30 +#: core/workspace/users/users.json #: public/js/frappe/views/reports/query_report.js:1789 #: public/js/frappe/views/reports/report_view.js:1666 msgid "User Permissions" @@ -27822,12 +27542,6 @@ msgctxt "Button in list view menu" msgid "User Permissions" msgstr "" -#. Label of a Link in the Users Workspace -#: core/workspace/users/users.json -msgctxt "User Permission" -msgid "User Permissions" -msgstr "" - #: core/page/permission_manager/permission_manager_help.html:32 msgid "User Permissions are used to limit users to specific records." msgstr "" @@ -27872,14 +27586,9 @@ msgstr "" #. Label of the user_type (Link) field in DocType 'User' #. Name of a DocType -#: core/doctype/user/user.json core/doctype/user_type/user_type.json -#: core/doctype/user_type/user_type.py:82 -msgid "User Type" -msgstr "" - #. Label of a shortcut in the Users Workspace -#: core/workspace/users/users.json -msgctxt "User Type" +#: core/doctype/user/user.json core/doctype/user_type/user_type.json +#: core/doctype/user_type/user_type.py:82 core/workspace/users/users.json msgid "User Type" msgstr "" @@ -27940,7 +27649,7 @@ msgstr "" msgid "User with email: {0} does not exist in the system. Please ask 'System Administrator' to create the user for you." msgstr "" -#: core/doctype/user/user.py:491 +#: core/doctype/user/user.py:495 msgid "User {0} cannot be deleted" msgstr "" @@ -27948,7 +27657,7 @@ msgstr "" msgid "User {0} cannot be disabled" msgstr "" -#: core/doctype/user/user.py:571 +#: core/doctype/user/user.py:575 msgid "User {0} cannot be renamed" msgstr "" @@ -27969,7 +27678,7 @@ msgstr "" msgid "User {0} has requested for data deletion" msgstr "" -#: core/doctype/user/user.py:1334 +#: core/doctype/user/user.py:1338 msgid "User {0} impersonated as {1}" msgstr "" @@ -27997,7 +27706,7 @@ msgstr "" msgid "Username" msgstr "" -#: core/doctype/user/user.py:656 +#: core/doctype/user/user.py:660 msgid "Username {0} already exists" msgstr "" @@ -28456,14 +28165,10 @@ msgid "Weak" msgstr "" #. Name of a DocType -#: website/doctype/web_form/web_form.json -msgid "Web Form" -msgstr "" - #. Label of a Link in the Website Workspace #. Label of a shortcut in the Website Workspace +#: website/doctype/web_form/web_form.json #: website/workspace/website/website.json -msgctxt "Web Form" msgid "Web Form" msgstr "" @@ -28483,14 +28188,10 @@ msgid "Web Form List Column" msgstr "" #. Name of a DocType -#: website/doctype/web_page/web_page.json -msgid "Web Page" -msgstr "" - #. Label of a Link in the Website Workspace #. Label of a shortcut in the Website Workspace +#: website/doctype/web_page/web_page.json #: website/workspace/website/website.json -msgctxt "Web Page" msgid "Web Page" msgstr "" @@ -28541,14 +28242,10 @@ msgstr "" #. Name of a DocType #. Label of the webhook (Link) field in DocType 'Webhook Request Log' +#. Label of a Link in the Integrations Workspace #: integrations/doctype/webhook/webhook.json #: integrations/doctype/webhook_request_log/webhook_request_log.json -msgid "Webhook" -msgstr "" - -#. Label of a Link in the Integrations Workspace #: integrations/workspace/integrations/integrations.json -msgctxt "Webhook" msgid "Webhook" msgstr "" @@ -28639,13 +28336,9 @@ msgid "Website Meta Tag" msgstr "" #. Name of a DocType -#: website/doctype/website_route_meta/website_route_meta.json -msgid "Website Route Meta" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/website_route_meta/website_route_meta.json #: website/workspace/website/website.json -msgctxt "Website Route Meta" msgid "Website Route Meta" msgstr "" @@ -28655,13 +28348,9 @@ msgid "Website Route Redirect" msgstr "" #. Name of a DocType -#: website/doctype/website_script/website_script.json -msgid "Website Script" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/website_script/website_script.json #: website/workspace/website/website.json -msgctxt "Website Script" msgid "Website Script" msgstr "" @@ -28675,29 +28364,21 @@ msgid "Website Search Field must be a valid fieldname" msgstr "" #. Name of a DocType -#: website/doctype/website_settings/website_settings.json -msgid "Website Settings" -msgstr "" - #. Label of a Link in the Website Workspace #. Label of a shortcut in the Website Workspace +#: website/doctype/website_settings/website_settings.json #: website/workspace/website/website.json -msgctxt "Website Settings" msgid "Website Settings" msgstr "" #. Label of the website_sidebar (Link) field in DocType 'Web Form' #. Label of the website_sidebar (Link) field in DocType 'Web Page' #. Name of a DocType +#. Label of a Link in the Website Workspace #: website/doctype/web_form/web_form.json #: website/doctype/web_page/web_page.json #: website/doctype/website_sidebar/website_sidebar.json -msgid "Website Sidebar" -msgstr "" - -#. Label of a Link in the Website Workspace #: website/workspace/website/website.json -msgctxt "Website Sidebar" msgid "Website Sidebar" msgstr "" @@ -28707,13 +28388,9 @@ msgid "Website Sidebar Item" msgstr "" #. Name of a DocType -#: website/doctype/website_slideshow/website_slideshow.json -msgid "Website Slideshow" -msgstr "" - #. Label of a Link in the Website Workspace +#: website/doctype/website_slideshow/website_slideshow.json #: website/workspace/website/website.json -msgctxt "Website Slideshow" msgid "Website Slideshow" msgstr "" @@ -28724,14 +28401,10 @@ msgstr "" #. Label of the website_theme (Link) field in DocType 'Website Settings' #. Name of a DocType +#. Label of a Link in the Website Workspace #: website/doctype/website_settings/website_settings.json #: website/doctype/website_theme/website_theme.json -msgid "Website Theme" -msgstr "" - -#. Label of a Link in the Website Workspace #: website/workspace/website/website.json -msgctxt "Website Theme" msgid "Website Theme" msgstr "" @@ -28840,11 +28513,11 @@ msgstr "" msgid "Welcome Workspace" msgstr "" -#: core/doctype/user/user.py:369 +#: core/doctype/user/user.py:373 msgid "Welcome email sent" msgstr "" -#: core/doctype/user/user.py:430 +#: core/doctype/user/user.py:434 msgid "Welcome to {0}" msgstr "" @@ -28952,20 +28625,16 @@ msgstr "" #. Option for the 'Comment Type' (Select) field in DocType 'Comment' #. Option for the 'Comment Type' (Select) field in DocType 'Communication' #. Group in DocType's connections +#. Label of a Link in the Build Workspace #. Name of a DocType #: core/doctype/comment/comment.json #: core/doctype/communication/communication.json -#: core/doctype/doctype/doctype.json public/js/workflow_builder/store.js:129 +#: core/doctype/doctype/doctype.json core/workspace/build/build.json +#: public/js/workflow_builder/store.js:129 #: workflow/doctype/workflow/workflow.json msgid "Workflow" msgstr "" -#. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Workflow" -msgid "Workflow" -msgstr "" - #. Name of a DocType #: workflow/doctype/workflow_action/workflow_action.json #: workflow/doctype/workflow_action/workflow_action.py:438 @@ -29077,19 +28746,15 @@ msgid "Workflows allow you to define custom rules for the approval process of a msgstr "" #. Label of the workspace_section (Section Break) field in DocType 'User' +#. Label of a Link in the Build Workspace #. Name of a DocType -#: core/doctype/user/user.json desk/doctype/workspace/workspace.json +#: core/doctype/user/user.json core/workspace/build/build.json +#: desk/doctype/workspace/workspace.json #: public/js/frappe/ui/toolbar/search_utils.js:557 #: public/js/frappe/views/workspace/workspace.js:10 msgid "Workspace" msgstr "" -#. Label of a Link in the Build Workspace -#: core/workspace/build/build.json -msgctxt "Workspace" -msgid "Workspace" -msgstr "" - #: public/js/frappe/router.js:179 msgid "Workspace {0} does not exist" msgstr "" @@ -29134,15 +28799,15 @@ msgstr "" msgid "Workspace not found" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:1308 +#: public/js/frappe/views/workspace/workspace.js:1306 msgid "Workspace {0} Created Successfully" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:937 +#: public/js/frappe/views/workspace/workspace.js:935 msgid "Workspace {0} Deleted Successfully" msgstr "" -#: public/js/frappe/views/workspace/workspace.js:715 +#: public/js/frappe/views/workspace/workspace.js:713 msgid "Workspace {0} Edited Successfully" msgstr "" @@ -29469,19 +29134,19 @@ msgstr "" msgid "You cannot unset 'Read Only' for field {0}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:121 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:125 msgid "You changed the value of {0}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:110 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:114 msgid "You changed the value of {0} {1}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:183 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:191 msgid "You changed the values for {0}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:172 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:180 msgid "You changed the values for {0} {1}" msgstr "" @@ -29828,7 +29493,7 @@ msgstr "" msgid "`job_id` paramater is required for deduplication." msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:219 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:232 msgid "added rows for {0}" msgstr "" @@ -30308,7 +29973,7 @@ msgstr "" msgid "red" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:221 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:234 msgid "removed rows for {0}" msgstr "" @@ -30730,19 +30395,19 @@ msgstr "" msgid "{0} cannot be hidden and mandatory without any default value" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:124 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:128 msgid "{0} changed the value of {1}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:115 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:119 msgid "{0} changed the value of {1} {2}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:186 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:194 msgid "{0} changed the values for {1}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:177 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:185 msgid "{0} changed the values for {1} {2}" msgstr "" @@ -30815,11 +30480,11 @@ msgstr "" msgid "{0} format could not be determined from the values in this column. Defaulting to {1}." msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:97 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:101 msgid "{0} from {1} to {2}" msgstr "" -#: public/js/frappe/form/footer/version_timeline_content_builder.js:157 +#: public/js/frappe/form/footer/version_timeline_content_builder.js:165 msgid "{0} from {1} to {2} in row #{3}" msgstr "" @@ -31018,7 +30683,7 @@ msgstr "" msgid "{0} items selected" msgstr "" -#: core/doctype/user/user.py:1343 +#: core/doctype/user/user.py:1347 msgid "{0} just impersonated as you. They gave this reason: {1}" msgstr "" @@ -31372,7 +31037,7 @@ msgstr "" #: contacts/doctype/address/address.js:35 #: contacts/doctype/contact/contact.js:88 -#: public/js/frappe/views/workspace/workspace.js:211 +#: public/js/frappe/views/workspace/workspace.js:209 msgid "{0}: {1}" msgstr "" @@ -31410,7 +31075,6 @@ msgstr "" #. Count format of shortcut in the Website Workspace #: website/workspace/website/website.json -msgctxt "Blogger" msgid "{} Active" msgstr "" @@ -31428,13 +31092,6 @@ msgstr "" #. Count format of shortcut in the Website Workspace #: website/workspace/website/website.json -msgctxt "Blog Post" -msgid "{} Published" -msgstr "" - -#. Count format of shortcut in the Website Workspace -#: website/workspace/website/website.json -msgctxt "Web Page" msgid "{} Published" msgstr "" From 05bf4bb5a499215bacccfa7247c361e271672f76 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 5 Aug 2024 17:13:19 +0530 Subject: [PATCH 156/176] chore(deleted_document): don't create feed entry on deletion Signed-off-by: Akhil Narang --- frappe/core/doctype/deleted_document/deleted_document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/deleted_document/deleted_document.py b/frappe/core/doctype/deleted_document/deleted_document.py index be5fc1b0ff..dcb25be677 100644 --- a/frappe/core/doctype/deleted_document/deleted_document.py +++ b/frappe/core/doctype/deleted_document/deleted_document.py @@ -26,7 +26,7 @@ class DeletedDocument(Document): restored: DF.Check # end: auto-generated types - pass + no_feed_on_delete = True @staticmethod def clear_old_logs(days=180): From ff0bec5838a33a307ee3637869893f5300823efb Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Mon, 5 Aug 2024 14:28:19 +0200 Subject: [PATCH 157/176] perf(utils): Lazy load flags img in frappe.utils.flag --- frappe/public/js/frappe/utils/utils.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index ff534141af..c3df8e1987 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1213,9 +1213,7 @@ Object.assign(frappe.utils, { }, flag(country_code) { - return ``; + return ``; }, make_chart(wrapper, custom_options = {}) { From 1c35f2216f63111e92c6c3a3ec044f9b146f854d Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Mon, 5 Aug 2024 18:01:30 +0530 Subject: [PATCH 158/176] fix(XLSX): remove unsupported characters from sheet title --- frappe/utils/xlsxutils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/utils/xlsxutils.py b/frappe/utils/xlsxutils.py index 9442a4c367..53b44bd5ca 100644 --- a/frappe/utils/xlsxutils.py +++ b/frappe/utils/xlsxutils.py @@ -8,6 +8,7 @@ import xlrd from openpyxl import load_workbook from openpyxl.styles import Font from openpyxl.utils import get_column_letter +from openpyxl.workbook.child import INVALID_TITLE_REGEX import frappe from frappe.utils.html_utils import unescape_html @@ -21,7 +22,8 @@ def make_xlsx(data, sheet_name, wb=None, column_widths=None): if wb is None: wb = openpyxl.Workbook(write_only=True) - ws = wb.create_sheet(sheet_name, 0) + sheet_name_sanitized = INVALID_TITLE_REGEX.sub(" ", sheet_name) + ws = wb.create_sheet(sheet_name_sanitized, 0) for i, column_width in enumerate(column_widths): if column_width: From 279c365916000517cdee9308aac887e058d2b956 Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Tue, 6 Aug 2024 09:29:28 +0530 Subject: [PATCH 159/176] fix: field sorting in listview (#27187) * fix: field sorting in listview * fix: field sorting in listview --- frappe/public/js/frappe/ui/sort_selector.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/frappe/public/js/frappe/ui/sort_selector.js b/frappe/public/js/frappe/ui/sort_selector.js index ef19905015..33cdb28f04 100644 --- a/frappe/public/js/frappe/ui/sort_selector.js +++ b/frappe/public/js/frappe/ui/sort_selector.js @@ -103,15 +103,13 @@ frappe.ui.SortSelector = class SortSelector { var { meta_sort_field, meta_sort_order } = this.get_meta_sort_field(); - if (!this.args.sort_by) { - if (meta_sort_field) { - this.args.sort_by = meta_sort_field; - this.args.sort_order = meta_sort_order; - } else { - // default - this.args.sort_by = "creation"; - this.args.sort_order = "desc"; - } + if (meta_sort_field) { + this.args.sort_by = meta_sort_field; + this.args.sort_order = meta_sort_order; + } else { + // default + this.args.sort_by = "creation"; + this.args.sort_order = "desc"; } if (!this.args.sort_by_label) { @@ -175,11 +173,11 @@ frappe.ui.SortSelector = class SortSelector { }; } - if (meta.sort_field && meta.sort_field.includes(",")) { + if (meta.sort_field) { var parts = meta.sort_field.split(",")[0].split(" "); return { meta_sort_field: parts[0], - meta_sort_order: parts[1], + meta_sort_order: meta.sort_order ? meta.sort_order.toLowerCase() : "", }; } else { return { From ae2ffa8c7e260ed5e5480025d7be04a0693c28f7 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Tue, 6 Aug 2024 12:38:29 +0530 Subject: [PATCH 160/176] fix(auto_email_report): ensure that a report is selected before we try to apply filters Signed-off-by: Akhil Narang --- frappe/email/doctype/auto_email_report/auto_email_report.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.js b/frappe/email/doctype/auto_email_report/auto_email_report.js index a6ceb08077..991f83bbd5 100644 --- a/frappe/email/doctype/auto_email_report/auto_email_report.js +++ b/frappe/email/doctype/auto_email_report/auto_email_report.js @@ -71,6 +71,9 @@ frappe.ui.form.on("Auto Email Report", { } }, show_filters: async function (frm) { + if (!frm.doc.report) { + return; + } var wrapper = $(frm.get_field("filters_display").wrapper); wrapper.empty(); let reference_report = frappe.query_reports[frm.doc.report]; From 366282555902b72123c7368a9a33fe47d7dc6bfb Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Tue, 6 Aug 2024 19:49:01 +0530 Subject: [PATCH 161/176] refactor(Frappe Mail): pass `last_synced_at` in system timezone --- frappe/email/frappemail.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/frappe/email/frappemail.py b/frappe/email/frappemail.py index a4bcf9b5c2..84ef6166f5 100644 --- a/frappe/email/frappemail.py +++ b/frappe/email/frappemail.py @@ -105,7 +105,7 @@ class FrappeMail: endpoint = "/api/method/mail.api.inbound.pull_raw" if last_synced_at: - last_synced_at = convert_to_utc(last_synced_at) + last_synced_at = add_or_update_tzinfo(last_synced_at) data = {"mailbox": self.mailbox, "limit": limit, "last_synced_at": last_synced_at} headers = {"X-Site": frappe.utils.get_url()} @@ -115,13 +115,15 @@ class FrappeMail: return {"latest_messages": response["mails"], "last_synced_at": last_synced_at} -def convert_to_utc(date_time: datetime | str, from_timezone: str | None = None) -> str: - """Converts datetime to UTC timezone.""" +def add_or_update_tzinfo(date_time: datetime | str, timezone: str | None = None) -> str: + """Adds or updates timezone to the datetime.""" - dt = ( - pytz.timezone(from_timezone or get_system_timezone()) - .localize(get_datetime(date_time)) - .astimezone(pytz.utc) - ) + date_time = get_datetime(date_time) + target_tz = pytz.timezone(timezone or get_system_timezone()) - return get_datetime_str(dt) + if date_time.tzinfo is None: + date_time = target_tz.localize(date_time) + else: + date_time = date_time.astimezone(target_tz) + + return str(date_time) From 519bdec3e9b3e4f5a60886aa35ef3a8aff449608 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 7 Aug 2024 09:21:57 +0530 Subject: [PATCH 162/176] fix(test): complete setup before running UI tests --- .../doctype/navbar_settings/navbar_settings.py | 14 ++++++-------- frappe/utils/install.py | 2 ++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py index 68223f299f..1d0848a751 100644 --- a/frappe/core/doctype/navbar_settings/navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/navbar_settings.py @@ -65,22 +65,20 @@ def sync_standard_items(): def sync_table(key, hook): navbar_settings = NavbarSettings("Navbar Settings") existing_items = {d.item_label: d for d in navbar_settings.get(key)} - new_items = {} + all_items = {} # add new items count = 0 # matain count because list may come from seperate apps for item in frappe.get_hooks(hook): if item.get("item_label") not in existing_items: navbar_settings.append(key, item, count) - new_items[item.get("item_label")] = True + all_items[item.get("item_label")] = True count += 1 # remove unused items - def fn(item): - if item.is_standard and (item.item_label not in new_items): - return False - else: - return True + items = navbar_settings.get(key) + for item in navbar_settings.get(key): + if item.is_standard and (item.item_label not in all_items): + items.remove(item) - navbar_settings.set(key, filter(lambda item: fn, navbar_settings.get(key))) navbar_settings.save() diff --git a/frappe/utils/install.py b/frappe/utils/install.py index b389259877..6c788fdf7c 100644 --- a/frappe/utils/install.py +++ b/frappe/utils/install.py @@ -181,6 +181,8 @@ def complete_setup_wizard(): } ) + frappe.db.set_single_value("Website Settings", "workspace_setup_completed", 1) + def add_standard_navbar_items(): navbar_settings = frappe.get_single("Navbar Settings") From 0837a39335621a5a674a86c3f915ec3f0c95bde3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 7 Aug 2024 09:50:17 +0530 Subject: [PATCH 163/176] fix(test): complete workspace setup before running UI tests --- frappe/core/doctype/navbar_settings/navbar_settings.py | 8 ++++---- frappe/tests/ui_test_helpers.py | 2 ++ frappe/utils/install.py | 2 -- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py index 1d0848a751..39ebcd892a 100644 --- a/frappe/core/doctype/navbar_settings/navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/navbar_settings.py @@ -65,20 +65,20 @@ def sync_standard_items(): def sync_table(key, hook): navbar_settings = NavbarSettings("Navbar Settings") existing_items = {d.item_label: d for d in navbar_settings.get(key)} - all_items = {} + new_standard_items = {} # add new items count = 0 # matain count because list may come from seperate apps for item in frappe.get_hooks(hook): if item.get("item_label") not in existing_items: navbar_settings.append(key, item, count) - all_items[item.get("item_label")] = True + new_standard_items[item.get("item_label")] = True count += 1 # remove unused items items = navbar_settings.get(key) - for item in navbar_settings.get(key): - if item.is_standard and (item.item_label not in all_items): + for item in items: + if item.is_standard and (item.item_label not in new_standard_items): items.remove(item) navbar_settings.save() diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index e9746ae74c..1993795649 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -449,6 +449,8 @@ def create_test_user(username=None): user.save() + frappe.db.set_single_value("Website Settings", "workspace_setup_completed", 1) + @whitelist_for_tests def setup_tree_doctype(): diff --git a/frappe/utils/install.py b/frappe/utils/install.py index 6c788fdf7c..b389259877 100644 --- a/frappe/utils/install.py +++ b/frappe/utils/install.py @@ -181,8 +181,6 @@ def complete_setup_wizard(): } ) - frappe.db.set_single_value("Website Settings", "workspace_setup_completed", 1) - def add_standard_navbar_items(): navbar_settings = frappe.get_single("Navbar Settings") From 0a00b40ceee3d2b40057b4b9d9140d7c007ac7d0 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 7 Aug 2024 10:01:41 +0530 Subject: [PATCH 164/176] fix(test): complete workspace setup before running UI tests --- frappe/core/doctype/navbar_settings/navbar_settings.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py index 39ebcd892a..18b9ff1ea7 100644 --- a/frappe/core/doctype/navbar_settings/navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/navbar_settings.py @@ -77,8 +77,7 @@ def sync_table(key, hook): # remove unused items items = navbar_settings.get(key) - for item in items: - if item.is_standard and (item.item_label not in new_standard_items): - items.remove(item) + items = [item for item in items if not (item.is_standard and (item.item_label not in new_standard_items))] + navbar_settings.set(key, items) navbar_settings.save() From 036bdf0445e37cda99ff9933f20fc54fe67cadbc Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Mon, 22 Jul 2024 17:36:18 +0200 Subject: [PATCH 165/176] fix(grid): Hide backdrop when deleting row in modal --- frappe/public/js/frappe/form/grid_row.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index a12aab162b..b6688d754e 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -95,11 +95,10 @@ export default class GridRow { remove() { var me = this; if (this.grid.is_editable()) { + if (this.get_open_form()) { + this.hide_form(); + } if (this.frm) { - if (this.get_open_form()) { - this.hide_form(); - } - frappe .run_serially([ () => { From 057d32a02daac7b15a6a46a11f7ba9c241443d49 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 7 Aug 2024 18:16:52 +0530 Subject: [PATCH 166/176] fix(test): complete workspace setup before running UI tests --- .../navbar_settings/navbar_settings.py | 20 ------------------- frappe/patches.txt | 2 +- frappe/tests/ui_test_helpers.py | 2 +- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py index 18b9ff1ea7..55e33cd61a 100644 --- a/frappe/core/doctype/navbar_settings/navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/navbar_settings.py @@ -22,26 +22,6 @@ class NavbarSettings(Document): settings_dropdown: DF.Table[NavbarItem] # end: auto-generated types - def validate(self): - self.validate_standard_navbar_items() - - def validate_standard_navbar_items(self): - doc_before_save = self.get_doc_before_save() - - if not doc_before_save: - return - - before_save_items = [ - item - for item in doc_before_save.help_dropdown + doc_before_save.settings_dropdown - if item.is_standard - ] - - after_save_items = [item for item in self.help_dropdown + self.settings_dropdown if item.is_standard] - - if not frappe.flags.in_patch and (len(before_save_items) > len(after_save_items)): - frappe.throw(_("Please hide the standard navbar items instead of deleting them")) - def get_app_logo(): app_logo = frappe.db.get_single_value("Navbar Settings", "app_logo", cache=True) diff --git a/frappe/patches.txt b/frappe/patches.txt index 275e667a49..cead1d85ad 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -237,5 +237,5 @@ frappe.patches.v15_0.migrate_session_data frappe.custom.doctype.property_setter.patches.remove_invalid_fetch_from_expressions frappe.patches.v16_0.switch_default_sort_order frappe.integrations.doctype.oauth_client.patches.set_default_allowed_role_in_oauth_client -execute:frappe.db.set_single_value("Website Settings", "workspace_setup_completed", 1) +execute:frappe.db.set_single_value("Workspace Settings", "workspace_setup_completed", 1) diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index 1993795649..4347434959 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -449,7 +449,7 @@ def create_test_user(username=None): user.save() - frappe.db.set_single_value("Website Settings", "workspace_setup_completed", 1) + frappe.db.set_single_value("Workspace Settings", "workspace_setup_completed", 1) @whitelist_for_tests From d4e7551481665124c3b5a7c087362af92fd18b70 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 7 Aug 2024 20:41:32 +0530 Subject: [PATCH 167/176] fix(minor): add column break in workspace settings modal --- .../doctype/workspace_settings/workspace_settings.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frappe/desk/doctype/workspace_settings/workspace_settings.js b/frappe/desk/doctype/workspace_settings/workspace_settings.js index 5a8525b80c..d1ba550205 100644 --- a/frappe/desk/doctype/workspace_settings/workspace_settings.js +++ b/frappe/desk/doctype/workspace_settings/workspace_settings.js @@ -8,8 +8,11 @@ frappe.ui.form.on("Workspace Settings", { let workspace_visibilty = JSON.parse(frm.doc.workspace_visibility_json || "{}"); // build fields from workspaces + let cnt = 0, + column_added = false; for (let w of frappe.boot.allowed_workspaces) { if (w.public) { + cnt++; frm.docfields.push({ fieldtype: "Check", fieldname: w.name, @@ -17,6 +20,12 @@ frappe.ui.form.on("Workspace Settings", { initial_value: workspace_visibilty[w.name] !== 0, // not set is also visible }); } + + if (cnt >= frappe.boot.allowed_workspaces.length / 2 && !column_added) { + // add column break to split into 2 columns + frm.docfields.push({ fieldtype: "Column Break" }); + column_added = true; + } } frappe.temp = frm; From 71eb3704bd9042d517e5e0b010a7629fe9f93f88 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:28:32 +0200 Subject: [PATCH 168/176] fix: preserve exif data in optimized image (#27341) --- frappe/utils/image.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/utils/image.py b/frappe/utils/image.py index ecffe21fed..bae933c224 100644 --- a/frappe/utils/image.py +++ b/frappe/utils/image.py @@ -52,6 +52,7 @@ def optimize_image(content, content_type, max_width=1024, max_height=768, optimi try: image = Image.open(io.BytesIO(content)) + exif = image.getexif() width, height = image.size max_height = max(min(max_height, height * 0.8), 200) max_width = max(min(max_width, width * 0.8), 200) @@ -66,6 +67,7 @@ def optimize_image(content, content_type, max_width=1024, max_height=768, optimi optimize=optimize, quality=quality, save_all=True if image_format == "gif" else None, + exif=exif, ) optimized_content = output.getvalue() return optimized_content if len(optimized_content) < len(content) else content From e57ca797837cdc61e55228161a96664738904d73 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:32:56 +0200 Subject: [PATCH 169/176] feat: flesh out boilerplate for script report (#27301) --- .../doctype/report/boilerplate/controller.js | 11 +++-- .../doctype/report/boilerplate/controller.py | 43 ++++++++++++++++++- pyproject.toml | 3 ++ 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/report/boilerplate/controller.js b/frappe/core/doctype/report/boilerplate/controller.js index b7a53df088..6aef67307e 100644 --- a/frappe/core/doctype/report/boilerplate/controller.js +++ b/frappe/core/doctype/report/boilerplate/controller.js @@ -2,7 +2,12 @@ // For license information, please see license.txt frappe.query_reports["{name}"] = {{ - "filters": [ - - ] + filters: [ + // {{ + // "fieldname": "my_filter", + // "label": __("My Filter"), + // "fieldtype": "Data", + // "reqd": 1, + // }}, + ], }}; diff --git a/frappe/core/doctype/report/boilerplate/controller.py b/frappe/core/doctype/report/boilerplate/controller.py index dd4339dd5f..53810436b2 100644 --- a/frappe/core/doctype/report/boilerplate/controller.py +++ b/frappe/core/doctype/report/boilerplate/controller.py @@ -2,8 +2,47 @@ # For license information, please see license.txt # import frappe +from frappe import _ -def execute(filters=None): - columns, data = [], [] +def execute(filters: dict | None = None): + """Return columns and data for the report. + + This is the main entry point for the report. It accepts the filters as a + dictionary and should return columns and data. It is called by the framework + every time the report is refreshed or a filter is updated. + """ + columns = get_columns() + data = get_data() + return columns, data + + +def get_columns() -> list[dict]: + """Return columns for the report. + + One field definition per column, just like a DocType field definition. + """ + return [ + {{ + "label": _("Column 1"), + "fieldname": "column_1", + "fieldtype": "Data", + }}, + {{ + "label": _("Column 2"), + "fieldname": "column_2", + "fieldtype": "Int", + }}, + ] + + +def get_data() -> list[list]: + """Return data for the report. + + The report data is a list of rows, with each row being a list of cell values. + """ + return [ + ["Row 1", 1], + ["Row 2", 2], + ] diff --git a/pyproject.toml b/pyproject.toml index 242a09f54d..bb58092aea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,6 +112,9 @@ freezegun = "~=1.2.2" [tool.ruff] line-length = 110 target-version = "py310" +exclude = [ + "**/doctype/*/boilerplate/*.py" # boilerplate are template strings, not valid python +] [tool.ruff.lint] select = [ From 0b47a255c2c6ed056746700386dc96cfafdeca11 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:33:37 +0200 Subject: [PATCH 170/176] fix: split attribution text into multiple lines (#27343) --- frappe/www/attribution.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/www/attribution.html b/frappe/www/attribution.html index 95c0ba5dc0..6a32de742e 100644 --- a/frappe/www/attribution.html +++ b/frappe/www/attribution.html @@ -8,8 +8,8 @@

    {{ _("Attribution") }}

    - {{ _("This software is built on top of many open source packages. We would like to thank the authors of these - packages for their contribution.") }} + {{ _("This software is built on top of many open source packages.") }} + {{ _("We would like to thank the authors of these packages for their contribution.") }}

    {% for app_info in apps %} From 74d9c622bc12b05b0fb7b8ee248eab9eb99be102 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 8 Aug 2024 17:48:22 +0530 Subject: [PATCH 171/176] fix(minor): Quick Entry now subclasses from Dialog --- frappe/public/js/frappe/form/quick_entry.js | 47 ++++++++++--------- .../public/js/frappe/form/script_manager.js | 1 + frappe/public/js/frappe/ui/dialog.js | 20 ++++---- frappe/public/js/frappe/ui/field_group.js | 41 ++++++++++++++++ 4 files changed, 74 insertions(+), 35 deletions(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 1a535ce666..0c43fb70ef 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -25,13 +25,15 @@ frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback, doc, fo return frappe.quick_entry.setup(); }; -frappe.ui.form.QuickEntryForm = class QuickEntryForm { +frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { constructor(doctype, after_insert, init_callback, doc, force) { + super({ auto_make: false }); this.doctype = doctype; this.after_insert = after_insert; this.init_callback = init_callback; this.doc = doc; this.force = force ? force : false; + this.dialog = this; // for backward compatibility } setup() { @@ -70,6 +72,8 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { df.fieldtype !== "Tab Break" ); }); + + this.mandatory = this.docfields; // backward compatibility } check_quick_entry_doc() { @@ -134,27 +138,24 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { render_dialog() { var me = this; + this.fields = this.docfields; + this.title = this.get_title(); - this.dialog = new frappe.ui.Dialog({ - title: this.get_title(), - fields: this.docfields, - doc: this.doc, - }); - + super.make(); this.register_primary_action(); this.render_edit_in_full_page_link(); this.setup_cmd_enter_for_save(); - this.dialog.onhide = () => (frappe.quick_entry = null); - this.dialog.show(); + this.onhide = () => (frappe.quick_entry = null); + this.show(); - this.dialog.refresh_dependency(); + this.refresh_dependency(); this.set_defaults(); this.script_manager.trigger("refresh"); if (this.init_callback) { - this.init_callback(this.dialog); + this.init_callback(this); } } @@ -170,7 +171,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { register_primary_action() { var me = this; - this.dialog.set_primary_action(__("Save"), function () { + this.set_primary_action(__("Save"), function () { if (me.dialog.working) { return; } @@ -247,14 +248,14 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { process_after_insert(r) { // delete the old doc - frappe.model.clear_doc(this.dialog.doc.doctype, this.dialog.doc.name); - this.dialog.doc = r.message; + frappe.model.clear_doc(this.doc.doctype, this.doc.name); + this.doc = r.message; if (this.script_manager.has_handler("after_save")) { return this.script_manager.trigger("after_save"); } else if (frappe._from_link) { - frappe.ui.form.update_calling_link(this.dialog.doc); + frappe.ui.form.update_calling_link(this.doc); } else if (this.after_insert) { - this.after_insert(this.dialog.doc); + this.after_insert(this.doc); } else { this.open_form_if_not_list(); } @@ -263,7 +264,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { setup_cmd_enter_for_save() { var me = this; // ctrl+enter to save - this.dialog.wrapper.keydown(function (e) { + this.wrapper.keydown(function (e) { if ((e.ctrlKey || e.metaKey) && e.which == 13) { if (!frappe.request.ajax_count) { // not already working -- double entry @@ -278,7 +279,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { open_form_if_not_list() { if (this.meta.issingle) return; let route = frappe.get_route(); - let doc = this.dialog.doc; + let doc = this.doc; if (route && !(route[0] === "List" && route[1] === doc.doctype)) { frappe.run_serially([() => frappe.set_route("Form", doc.doctype, doc.name)]); } @@ -286,17 +287,17 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { update_doc() { var me = this; - var data = this.dialog.get_values(true); + var data = this.get_values(true); $.each(data, function (key, value) { if (!is_null(value)) { me.dialog.doc[key] = value; } }); - return this.dialog.doc; + return this.doc; } open_doc(set_hooks) { - this.dialog.hide(); + this.hide(); this.update_doc(); if (set_hooks && this.after_insert) { frappe.route_options = frappe.route_options || {}; @@ -309,13 +310,13 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { render_edit_in_full_page_link() { if (this.force || this.hide_full_form_button) return; - this.dialog.add_custom_action(__("Edit Full Form"), () => this.open_doc(true)); + this.add_custom_action(__("Edit Full Form"), () => this.open_doc(true)); } set_defaults() { var me = this; // set defaults - $.each(this.dialog.fields_dict, function (fieldname, field) { + $.each(this.fields_dict, function (fieldname, field) { field.doctype = me.doc.doctype; field.docname = me.doc.name; diff --git a/frappe/public/js/frappe/form/script_manager.js b/frappe/public/js/frappe/form/script_manager.js index badce4460f..3ff3fb92cb 100644 --- a/frappe/public/js/frappe/form/script_manager.js +++ b/frappe/public/js/frappe/form/script_manager.js @@ -245,6 +245,7 @@ frappe.ui.form.ScriptManager = class ScriptManager { this.trigger("setup"); } + log_error(caller, e) { frappe.show_alert({ message: __("Error in Client Script."), indicator: "error" }); console.group && console.group(); diff --git a/frappe/public/js/frappe/ui/dialog.js b/frappe/public/js/frappe/ui/dialog.js index eea34bb65e..da288621b8 100644 --- a/frappe/public/js/frappe/ui/dialog.js +++ b/frappe/public/js/frappe/ui/dialog.js @@ -13,8 +13,10 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { this.display = false; this.is_dialog = true; - $.extend(this, { animate: true, size: null }, opts); - this.make(); + $.extend(this, { animate: true, size: null, auto_make: true }, opts); + if (this.auto_make) { + this.make(); + } } make() { @@ -127,10 +129,6 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { }); } - get $backdrop() { - return $(this.$wrapper.data("bs.modal")?._backdrop); - } - set_modal_size() { if (!this.fields) { this.size = ""; @@ -259,7 +257,7 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { this.$wrapper.removeClass("modal-minimize"); if (this.minimizable && this.is_minimized) { - this.$backdrop.show(); + $(".modal-backdrop").toggle(); this.is_minimized = false; } @@ -272,10 +270,6 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { } hide() { - if (this.animate && this.animation_speed === "slow") { - this.$wrapper.addClass("slow"); - this.$backdrop.addClass("slow"); - } this.$wrapper.modal("hide"); this.is_visible = false; } @@ -297,7 +291,7 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { } toggle_minimize() { - this.$backdrop.toggle(); + $(".modal-backdrop").toggle(); let modal = this.$wrapper.closest(".modal").toggleClass("modal-minimize"); modal.attr("tabindex") ? modal.removeAttr("tabindex") : modal.attr("tabindex", -1); this.is_minimized = !this.is_minimized; @@ -323,6 +317,8 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { action && action_button.click(action); } + + add_custom_button() {} }; frappe.ui.hide_open_dialog = () => { diff --git a/frappe/public/js/frappe/ui/field_group.js b/frappe/public/js/frappe/ui/field_group.js index 27fe08439c..4a1022ec9f 100644 --- a/frappe/public/js/frappe/ui/field_group.js +++ b/frappe/public/js/frappe/ui/field_group.js @@ -6,6 +6,8 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout { constructor(opts) { super(opts); this.dirty = false; + this.fetch_dict = {}; + $.each(this.fields || [], function (i, f) { if (!f.fieldname && f.label) { f.fieldname = f.label.replace(/ /g, "_").toLowerCase(); @@ -197,4 +199,43 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout { field.df[prop] = value; field.refresh(); } + + set_query(fieldname, opt1, opt2) { + if (opt2) { + // on child table + // set_query(fieldname, parent fieldname, query) + if (this.fields_dict[opt1]) + this.fields_dict[opt1].grid.get_field(fieldname).get_query = opt2; + } else { + // on parent table + // set_query(fieldname, query) + if (this.fields_dict[fieldname]) { + this.fields_dict[fieldname].get_query = opt1; + } + } + } + + // UTILITIES + add_fetch(link_field, source_field, target_field, target_doctype) { + /* + Example fetch dict to get sender_email from email_id field in sender: + { + "Notification": { + "sender": { + "sender_email": "email_id" + } + } + } + */ + + if (!target_doctype) target_doctype = "*"; + + // Target field kept as key because source field could be non-unique + this.fetch_dict.setDefault(target_doctype, {}).setDefault(link_field, {})[target_field] = + source_field; + } + + is_new() { + return this.doc.__islocal; + } }; From f337af53862a5e45e5c7db44d09ecc4c8dead151 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Thu, 8 Aug 2024 17:47:19 +0530 Subject: [PATCH 172/176] fix: check to ensure field is defined TypeError: Cannot read properties of undefined (reading 'qty') at .round_floats_in(../../../../../apps/frappe/frappe/public/js/frappe/model/model.js:793:25) at erpnext.TransactionControllerconversion_factor(../../../../../apps/erpnext/erpnext/public/js/controllers/transaction.js:1195:17) at erpnext.selling.SellingControllerconversion_factor(../../../../../apps/erpnext/erpnext/public/js/utils/sales_common.js:365:11) at (../../../../../apps/erpnext/erpnext/public/js/controllers/transaction.js:1254:16) Signed-off-by: Akhil Narang --- frappe/public/js/frappe/model/model.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/model/model.js b/frappe/public/js/frappe/model/model.js index 60270cace0..11a329e98e 100644 --- a/frappe/public/js/frappe/model/model.js +++ b/frappe/public/js/frappe/model/model.js @@ -790,7 +790,9 @@ $.extend(frappe.model, { } for (var i = 0, j = fieldnames.length; i < j; i++) { var fieldname = fieldnames[i]; - doc[fieldname] = flt(doc[fieldname], precision(fieldname, doc)); + if (doc[fieldname]) { + doc[fieldname] = flt(doc[fieldname], precision(fieldname, doc)); + } } }, From a6ab011208c90d6f6c80b0827caa6a943ccb3a3c Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 8 Aug 2024 21:01:49 +0530 Subject: [PATCH 173/176] fix(minor): quick_entry.js - use this.mandatory if set for backward compatibility --- frappe/public/js/frappe/form/quick_entry.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 0c43fb70ef..fbb02274db 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -72,8 +72,6 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { df.fieldtype !== "Tab Break" ); }); - - this.mandatory = this.docfields; // backward compatibility } check_quick_entry_doc() { @@ -138,6 +136,12 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { render_dialog() { var me = this; + + if (this.mandatory) { + // overridden in several places in erpnext + this.docfields = this.mandatory; + } + this.fields = this.docfields; this.title = this.get_title(); From 864c82bbb5cd5b483baf354a991b23153bf3c6cf Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 8 Aug 2024 21:50:24 +0530 Subject: [PATCH 174/176] fix(minor): quick_entry.js - getter/setter for mandatory property --- frappe/public/js/frappe/form/quick_entry.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index fbb02274db..3cfb3aa530 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -134,14 +134,21 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { this.script_manager.setup(); } + get mandatory() { + // Backwards compatibility + console.warn("QuickEntryForm: .mandatory is deprecated, use .docfields instead"); + return this.docfields; + } + + set mandatory(value) { + // Backwards compatibility + console.warn("QuickEntryForm: .mandatory is deprecated, use .docfields instead"); + this.docfields = value; + } + render_dialog() { var me = this; - if (this.mandatory) { - // overridden in several places in erpnext - this.docfields = this.mandatory; - } - this.fields = this.docfields; this.title = this.get_title(); From 8a2aa92389f22798b3ea7b640e1dc7b356dd0eaf Mon Sep 17 00:00:00 2001 From: gruener Date: Fri, 9 Aug 2024 05:57:07 +0200 Subject: [PATCH 175/176] =?UTF-8?q?fix:=20Fixes=20mariadb=20orm=20to=20ret?= =?UTF-8?q?urn=20list=20instead=20of=20tuple=20as=20the=20typisat=E2=80=A6?= =?UTF-8?q?=20(#27179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Fixes mariadb orm to return list instead of tuple as the typisation suggests it * fix: inverted fix for pg: Expect tuple as data_type for _transform_result * fix: Fixed failing upstream spec due to data_type change --- frappe/database/database.py | 2 +- frappe/database/postgres/database.py | 3 +++ frappe/tests/test_db.py | 28 +++++++++++++++++++++------- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index 1edd61926d..c7ce29de6a 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -144,7 +144,7 @@ class Database: def _transform_query(self, query: Query, values: QueryValues) -> tuple: return query, values - def _transform_result(self, result: list[tuple]) -> list[tuple]: + def _transform_result(self, result: list[tuple] | tuple[tuple]) -> tuple[tuple]: return result def _clean_up(self): diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index 56ae71a9ad..aa3f808a79 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -225,6 +225,9 @@ class PostgresDatabase(PostgresExceptionUtil, Database): ) return db_size[0].get("database_size") + def _transform_result(self, result: list[tuple] | tuple[tuple]) -> tuple[tuple]: + return tuple(result) if isinstance(result, list) else result + # pylint: disable=W0221 def sql(self, query, values=EmptyQueryValues, *args, **kwargs): return super().sql(modify_query(query), modify_values(values), *args, **kwargs) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 63c0dba7da..6d2994dd90 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -572,6 +572,20 @@ class TestDB(FrappeTestCase): frappe.db.rollback() + def test_get_list_return_value_data_type(self): + frappe.db.delete("Note") + + frappe.get_doc(doctype="Note", title="note1", content="something").insert() + frappe.get_doc(doctype="Note", title="note2", content="someting else").insert() + + note_docs = frappe.db.sql("select * from `tabNote`") + + # should return both records + self.assertEqual(len(note_docs), 2) + + # data-type should be list + self.assertIsInstance(note_docs, tuple) + @run_only_if(db_type_is.POSTGRES) def test_modify_query(self): from frappe.database.postgres.database import modify_query @@ -1111,9 +1125,9 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): if frappe.db.sql( """SELECT 1 - FROM information_schema.schemata - WHERE schema_name = 'alt_schema' - limit 1 """ + FROM information_schema.schemata + WHERE schema_name = 'alt_schema' + LIMIT 1 """ ): self.cleanup() @@ -1244,19 +1258,19 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') self.assertEqual( rows, - [ + ( ( "a", "b", - ) - ], + ), + ), ) # there should be a single row in the public table # when schema is changed to alt_schema, the alt_schema tables should be addressed by search path frappe.conf["db_schema"] = "alt_schema" frappe.db.connect() rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') - self.assertEqual(rows, []) # there are no records in the alt_schema table + self.assertEqual(rows, ()) # there are no records in the alt_schema table del frappe.conf["db_schema"] From ac0e46669d7e2eeffa871045010a90ea4032caf9 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 9 Aug 2024 13:49:09 +0200 Subject: [PATCH 176/176] fix: spec preview fields statically on the frontend --- .../email/doctype/notification/notification.js | 11 +++++++++-- .../email/doctype/notification/notification.py | 8 -------- frappe/integrations/doctype/webhook/webhook.js | 16 ++++++++++++---- frappe/integrations/doctype/webhook/webhook.py | 9 --------- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js index 5a7c8394a2..c11a0ec3a3 100644 --- a/frappe/email/doctype/notification/notification.js +++ b/frappe/email/doctype/notification/notification.js @@ -164,7 +164,6 @@ frappe.ui.form.on("Notification", { }, }; }); - frm.preview_fields = frm.doc.__onload.preview_fields; }, refresh: function (frm) { frappe.notification.setup_fieldname_select(frm); @@ -185,7 +184,15 @@ frappe.ui.form.on("Notification", { const args = { doc: frm.doc, doctype: frm.doc.document_type, - preview_fields: frm.preview_fields, + preview_fields: [ + { + label: __("Meets Condition?"), + fieldtype: "Data", + method: "preview_meets_condition", + }, + { label: __("Subject"), fieldtype: "Data", method: "preview_subject" }, + { label: __("Message"), fieldtype: "Code", method: "preview_message" }, + ], }; let dialog = new frappe.views.RenderPreviewer(args); return dialog; diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index 0e8a7bd4c1..2e7159d47b 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -73,14 +73,6 @@ class Notification(Document): """load message""" if self.is_standard: self.message = self.get_template() - self.set_onload( - "preview_fields", - [ - {"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"}, - {"label": _("Subject"), "fieldtype": "Data", "method": "preview_subject"}, - {"label": _("Message"), "fieldtype": "Code", "method": "preview_message"}, - ], - ) def autoname(self): if not self.name: diff --git a/frappe/integrations/doctype/webhook/webhook.js b/frappe/integrations/doctype/webhook/webhook.js index 168b4be446..38aed089f5 100644 --- a/frappe/integrations/doctype/webhook/webhook.js +++ b/frappe/integrations/doctype/webhook/webhook.js @@ -79,9 +79,6 @@ frappe.webhook = { }; frappe.ui.form.on("Webhook", { - onload: (frm) => { - frm.preview_fields = frm.doc.__onload.preview_fields; - }, refresh: (frm) => { frappe.webhook.set_fieldname_select(frm); frm.set_query( @@ -94,7 +91,18 @@ frappe.ui.form.on("Webhook", { const args = { doc: frm.doc, doctype: frm.doc.webhook_doctype, - preview_fields: frm.preview_fields, + preview_fields: [ + { + label: __("Meets Condition?"), + fieldtype: "Data", + method: "preview_meets_condition", + }, + { + label: __("Request Body"), + fieldtype: "Code", + method: "preview_request_body", + }, + ], }; let dialog = new frappe.views.RenderPreviewer(args); return dialog; diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 8ee5df1a25..952d25d31f 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -56,15 +56,6 @@ class Webhook(Document): webhook_secret: DF.Password | None # end: auto-generated types - def onload(self): - self.set_onload( - "preview_fields", - [ - {"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"}, - {"label": _("Request Body"), "fieldtype": "Code", "method": "preview_request_body"}, - ], - ) - def validate(self): self.validate_docevent() self.validate_condition()