From 5a55507e6d8b6401e5d3a5fd9e3e4853969bdf41 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 13 Jul 2022 20:17:31 +0530 Subject: [PATCH 01/23] fix: pass docfield for custom indicator formatter (#17501) --- frappe/public/js/frappe/form/formatters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index 3bf36c86af..5cf5a2f4f3 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -26,7 +26,7 @@ frappe.form.formatters = { if (df) { const std_df = frappe.meta.docfield_map[df.parent] && frappe.meta.docfield_map[df.parent][df.fieldname]; if (std_df && std_df.formatter && typeof std_df.formatter==='function') { - value = std_df.formatter(value); + value = std_df.formatter(value, df); } } return value; From 99d3fe3893ebef7732c8f7bad01925f90d9b5b68 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 12 Jul 2022 19:59:42 +0530 Subject: [PATCH 02/23] fix(dark theme): background color on version page --- frappe/core/doctype/version/version_view.html | 11 +++++----- frappe/public/scss/common/css_variables.scss | 4 ++++ frappe/public/scss/desk/dark.scss | 4 ++++ frappe/public/scss/desk/global.scss | 20 ++++++------------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/frappe/core/doctype/version/version_view.html b/frappe/core/doctype/version/version_view.html index 67f005ed4c..a17460ccc7 100644 --- a/frappe/core/doctype/version/version_view.html +++ b/frappe/core/doctype/version/version_view.html @@ -18,8 +18,8 @@ {% for item in data.changed %} {{ frappe.meta.get_label(doc.ref_doctype, item[0]) }} - {{ item[1] }} - {{ item[2] }} + {{ item[1] }} + {{ item[2] }} {% endfor %} @@ -43,8 +43,7 @@ {% for item in values %} {{ frappe.meta.get_label(doc.ref_doctype, item[0]) }} - + {% var item_keys = Object.keys(item[1]).sort(); %} @@ -86,8 +85,8 @@ - - + + {% endfor %} {% endfor %} diff --git a/frappe/public/scss/common/css_variables.scss b/frappe/public/scss/common/css_variables.scss index ab52c10e45..efcbe06920 100644 --- a/frappe/public/scss/common/css_variables.scss +++ b/frappe/public/scss/common/css_variables.scss @@ -262,6 +262,10 @@ $input-height: 28px !default; --checkbox-focus-shadow: 0 0 0 2px var(--gray-300); --checkbox-gradient: linear-gradient(180deg, #4AC3F8 -124.51%, var(--primary) 100%); + // "diff" colors + --diff-added: var(--green-100); + --diff-removed: var(--red-100); + --right-arrow-svg: url("data: image/svg+xml;utf8, "); --left-arrow-svg: url("data: image/svg+xml;utf8, "); } diff --git a/frappe/public/scss/desk/dark.scss b/frappe/public/scss/desk/dark.scss index c627d88f89..3d05ecd237 100644 --- a/frappe/public/scss/desk/dark.scss +++ b/frappe/public/scss/desk/dark.scss @@ -93,6 +93,10 @@ --shadow-base: 0px 4px 8px rgba(114, 176, 233, 0.06), 0px 0px 4px rgba(112, 172, 228, 0.12); + // "diff" colors + --diff-added: var(--green-800); + --diff-removed: var(--red-800); + // input --input-disabled-bg: none; diff --git a/frappe/public/scss/desk/global.scss b/frappe/public/scss/desk/global.scss index 6a85dea6dd..7466bdc874 100644 --- a/frappe/public/scss/desk/global.scss +++ b/frappe/public/scss/desk/global.scss @@ -579,22 +579,14 @@ details > summary:focus { color: var(--text-color); } - -.diffview .insert { - background-color: var(--green-100); -} - -.diffview .delete { - background-color: var(--red-100); +.diffview .insert, +.diff-add { + background-color: var(--diff-added); } -[data-theme="dark"] { - .diffview .insert { - background-color: var(--green-800); - } - .diffview .delete { - background-color: var(--red-800); - } +.diffview .delete, +.diff-remove { + background-color: var(--diff-removed); } // REDESIGN TODO: Handling of broken images? From 3a7c7ff18234bef055cc1c732a7c934fbe220746 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 12 Jul 2022 20:23:34 +0530 Subject: [PATCH 03/23] ci: ignore HTML files for server tests --- .github/helper/roulette.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/helper/roulette.py b/.github/helper/roulette.py index c240443e9a..554f4ae5f5 100644 --- a/.github/helper/roulette.py +++ b/.github/helper/roulette.py @@ -46,7 +46,7 @@ def is_ci(file): return ".github" in file def is_frontend_code(file): - return file.lower().endswith((".css", ".scss", ".less", ".sass", ".styl", ".js", ".ts", ".vue")) + return file.lower().endswith((".css", ".scss", ".less", ".sass", ".styl", ".js", ".ts", ".vue", ".html")) def is_docs(file): regex = re.compile(r'\.(md|png|jpg|jpeg|csv|svg)$|^.github|LICENSE') From 2c36874554e6c70fe08bf9d3a9c7b9d5d2be64f1 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 13 Jul 2022 12:39:43 +0530 Subject: [PATCH 04/23] style: add config for CSS and SCSS --- .editorconfig | 2 +- frappe/public/scss/common/css_variables.scss | 8 ++++---- frappe/public/scss/desk/dark.scss | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.editorconfig b/.editorconfig index d76f67cd7f..f4c7f1528c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,6 @@ trim_trailing_whitespace = true charset = utf-8 # python, js indentation settings -[{*.py,*.js,*.vue}] +[{*.py,*.js,*.vue,*.css,*.scss,*.html}] indent_style = tab indent_size = 4 diff --git a/frappe/public/scss/common/css_variables.scss b/frappe/public/scss/common/css_variables.scss index efcbe06920..0b6da84222 100644 --- a/frappe/public/scss/common/css_variables.scss +++ b/frappe/public/scss/common/css_variables.scss @@ -134,7 +134,7 @@ $input-height: 28px !default; --shadow-xs: rgba(0, 0, 0, 0.05) 0px 0.5px 0px 0px, rgba(0, 0, 0, 0.08) 0px 0px 0px 1px, rgba(0, 0, 0, 0.05) 0px 2px 4px 0px; --shadow-sm: 0px 1px 2px rgba(25, 39, 52, 0.05), 0px 0px 4px rgba(25, 39, 52, 0.1); - --shadow-base: 0px 4px 8px rgba(25, 39, 52, 0.06), 0px 0px 4px rgba(25, 39, 52, 0.12); + --shadow-base: 0px 4px 8px rgba(25, 39, 52, 0.06), 0px 0px 4px rgba(25, 39, 52, 0.12); --shadow-md: 0px 8px 14px rgba(25, 39, 52, 0.08), 0px 2px 6px rgba(25, 39, 52, 0.04); --shadow-lg: 0px 18px 22px rgba(25, 39, 52, 0.1), 0px 1px 10px rgba(0, 0, 0, 0.06), 0px 0.5px 5px rgba(25, 39, 52, 0.04); @@ -262,9 +262,9 @@ $input-height: 28px !default; --checkbox-focus-shadow: 0 0 0 2px var(--gray-300); --checkbox-gradient: linear-gradient(180deg, #4AC3F8 -124.51%, var(--primary) 100%); - // "diff" colors - --diff-added: var(--green-100); - --diff-removed: var(--red-100); + // "diff" colors + --diff-added: var(--green-100); + --diff-removed: var(--red-100); --right-arrow-svg: url("data: image/svg+xml;utf8, "); --left-arrow-svg: url("data: image/svg+xml;utf8, "); diff --git a/frappe/public/scss/desk/dark.scss b/frappe/public/scss/desk/dark.scss index 3d05ecd237..731ff4525d 100644 --- a/frappe/public/scss/desk/dark.scss +++ b/frappe/public/scss/desk/dark.scss @@ -91,11 +91,11 @@ --highlight-shadow: 1px 1px 10px var(--blue-900), 0px 0px 4px var(--blue-500); - --shadow-base: 0px 4px 8px rgba(114, 176, 233, 0.06), 0px 0px 4px rgba(112, 172, 228, 0.12); + --shadow-base: 0px 4px 8px rgba(114, 176, 233, 0.06), 0px 0px 4px rgba(112, 172, 228, 0.12); - // "diff" colors - --diff-added: var(--green-800); - --diff-removed: var(--red-800); + // "diff" colors + --diff-added: var(--green-800); + --diff-removed: var(--red-800); // input --input-disabled-bg: none; From 95f67b8de85267d6620f9ea311bf07bd45a1fc91 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 14 Jul 2022 13:14:58 +0530 Subject: [PATCH 05/23] fix: ignore empty part in naming series (#17508) on v13 doc.get("") returns entire doc dictionary, this gets strigified and becomes a problem for naming. --- frappe/model/naming.py | 21 +++++++++++++++++++-- frappe/tests/test_naming.py | 27 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index 0ce6704c39..49a58da314 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -1,6 +1,7 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE +import datetime import re from typing import TYPE_CHECKING, Callable, Optional @@ -23,6 +24,17 @@ NAMING_SERIES_PATTERN = re.compile(r"^[\w\- \/.#{}]+$", re.UNICODE) BRACED_PARAMS_PATTERN = re.compile(r"(\{[\w | #]+\})") +# Types that can be using in naming series fields +NAMING_SERIES_PART_TYPES = ( + int, + str, + datetime.datetime, + datetime.date, + datetime.time, + datetime.timedelta, +) + + class InvalidNamingSeriesError(frappe.ValidationError): pass @@ -298,6 +310,9 @@ def parse_naming_series( series_set = False today = now_datetime() for e in parts: + if not e: + continue + part = "" if e.startswith("#"): if not series_set: @@ -320,14 +335,16 @@ def parse_naming_series( part = frappe.defaults.get_user_default("fiscal_year") elif e.startswith("{") and doc: e = e.replace("{", "").replace("}", "") - part = (cstr(doc.get(e)) or "").strip() + part = doc.get(e) elif doc and doc.get(e): - part = (cstr(doc.get(e)) or "").strip() + part = doc.get(e) else: part = e if isinstance(part, str): name += part + elif isinstance(part, NAMING_SERIES_PART_TYPES): + name += cstr(part).strip() return name diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index 5feaad6f9b..9f5b46a4d1 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -9,6 +9,7 @@ from frappe.model.naming import ( append_number_if_name_exists, determine_consecutive_week_number, getseries, + parse_naming_series, revert_series_if_last, ) from frappe.tests.utils import FrappeTestCase @@ -342,6 +343,32 @@ class TestNaming(FrappeTestCase): name.startswith("KOOH-on_update"), f"incorrect name generated {name}, missing field value" ) + def test_naming_with_empty_part(self): + # check naming with empty part (duplicate dots) + + webhook = frappe.new_doc("Webhook") + webhook.webhook_docevent = "on_update" + + series = "KOOH-..{webhook_docevent}.-.####" + + name = parse_naming_series(series, doc=webhook) + self.assertTrue( + name.startswith("KOOH-on_update"), f"incorrect name generated {name}, missing field value" + ) + + def test_naming_with_unsupported_part(self): + # check naming with empty part (duplicate dots) + + webhook = frappe.new_doc("Webhook") + webhook.webhook_docevent = {"dict": "not supported"} + + series = "KOOH-..{webhook_docevent}.-.####" + + name = parse_naming_series(series, doc=webhook) + self.assertTrue( + name.startswith("KOOH-"), f"incorrect name generated {name}, missing field value" + ) + def make_invalid_todo(): frappe.get_doc({"doctype": "ToDo", "description": "Test"}).insert(set_name="ToDo") From a8f86abbd8fa16c18eb3b621e90c5f77eb69d1d0 Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Thu, 14 Jul 2022 14:09:00 +0530 Subject: [PATCH 06/23] refactor: Replaced blog's feedback with comment's comment_type='Like' (#17479) --- frappe/core/doctype/comment/comment.json | 14 +++- frappe/core/doctype/feedback/feedback.js | 8 -- frappe/core/doctype/feedback/feedback.json | 73 ------------------ frappe/core/doctype/feedback/feedback.py | 9 --- frappe/core/doctype/feedback/test_feedback.py | 42 ---------- frappe/patches.txt | 1 + .../v14_0/setup_likes_from_feedback.py | 30 ++++++++ .../templates/includes/comments/comment.html | 2 +- .../templates/includes/comments/comments.html | 7 +- .../templates/includes/comments/comments.py | 8 +- .../templates/includes/feedback/__init__.py | 0 .../templates/includes/feedback/feedback.py | 55 ------------- .../includes/likes}/__init__.py | 0 .../feedback.html => likes/likes.html} | 24 +++--- frappe/templates/includes/likes/likes.py | 77 +++++++++++++++++++ .../website/doctype/blog_post/blog_post.json | 18 ++--- frappe/website/doctype/blog_post/blog_post.py | 52 ++++++------- .../blog_post/templates/blog_post.html | 19 ++++- .../doctype/blog_post/test_blog_post.py | 23 ++++++ .../doctype/blog_settings/blog_settings.json | 18 ++--- .../doctype/blog_settings/blog_settings.py | 4 +- 21 files changed, 221 insertions(+), 263 deletions(-) delete mode 100644 frappe/core/doctype/feedback/feedback.js delete mode 100644 frappe/core/doctype/feedback/feedback.json delete mode 100644 frappe/core/doctype/feedback/feedback.py delete mode 100644 frappe/core/doctype/feedback/test_feedback.py create mode 100644 frappe/patches/v14_0/setup_likes_from_feedback.py delete mode 100644 frappe/templates/includes/feedback/__init__.py delete mode 100644 frappe/templates/includes/feedback/feedback.py rename frappe/{core/doctype/feedback => templates/includes/likes}/__init__.py (100%) rename frappe/templates/includes/{feedback/feedback.html => likes/likes.html} (77%) create mode 100644 frappe/templates/includes/likes/likes.py diff --git a/frappe/core/doctype/comment/comment.json b/frappe/core/doctype/comment/comment.json index fe465f46bd..9f27e7e7be 100644 --- a/frappe/core/doctype/comment/comment.json +++ b/frappe/core/doctype/comment/comment.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2019-02-07 10:10:46.845678", "doctype": "DocType", "editable_grid": 1, @@ -17,7 +18,8 @@ "link_name", "reference_owner", "section_break_10", - "content" + "content", + "ip_address" ], "fields": [ { @@ -102,9 +104,16 @@ "ignore_xss_filter": 1, "in_list_view": 1, "label": "Content" + }, + { + "fieldname": "ip_address", + "fieldtype": "Data", + "hidden": 1, + "label": "IP Address" } ], - "modified": "2019-09-02 21:00:10.784787", + "links": [], + "modified": "2022-07-12 17:35:31.774137", "modified_by": "Administrator", "module": "Core", "name": "Comment", @@ -138,6 +147,7 @@ "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "title_field": "comment_type", "track_changes": 1 } \ No newline at end of file diff --git a/frappe/core/doctype/feedback/feedback.js b/frappe/core/doctype/feedback/feedback.js deleted file mode 100644 index 131f0e19d8..0000000000 --- a/frappe/core/doctype/feedback/feedback.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2021, Frappe Technologies and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Feedback', { - // refresh: function(frm) { - - // } -}); diff --git a/frappe/core/doctype/feedback/feedback.json b/frappe/core/doctype/feedback/feedback.json deleted file mode 100644 index f8380cfda6..0000000000 --- a/frappe/core/doctype/feedback/feedback.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "actions": [], - "creation": "2021-06-03 19:02:55.328423", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "reference_doctype", - "reference_name", - "column_break_3", - "like", - "ip_address" - ], - "fields": [ - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "fieldname": "reference_doctype", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Reference Document Type", - "options": "\nBlog Post" - }, - { - "fieldname": "reference_name", - "fieldtype": "Dynamic Link", - "in_list_view": 1, - "label": "Reference Name", - "options": "reference_doctype", - "reqd": 1 - }, - { - "fieldname": "ip_address", - "fieldtype": "Data", - "hidden": 1, - "label": "IP Address", - "read_only": 1 - }, - { - "default": "0", - "fieldname": "like", - "fieldtype": "Check", - "label": "Like" - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-11-10 20:53:21.255593", - "modified_by": "Administrator", - "module": "Core", - "name": "Feedback", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "reference_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/frappe/core/doctype/feedback/feedback.py b/frappe/core/doctype/feedback/feedback.py deleted file mode 100644 index c616787e4b..0000000000 --- a/frappe/core/doctype/feedback/feedback.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies and contributors -# License: MIT. See LICENSE - -# import frappe -from frappe.model.document import Document - - -class Feedback(Document): - pass diff --git a/frappe/core/doctype/feedback/test_feedback.py b/frappe/core/doctype/feedback/test_feedback.py deleted file mode 100644 index e8e29e75ae..0000000000 --- a/frappe/core/doctype/feedback/test_feedback.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies and Contributors -# License: MIT. See LICENSE - -import unittest - -import frappe - - -class TestFeedback(unittest.TestCase): - def tearDown(self): - frappe.form_dict.reference_doctype = None - frappe.form_dict.reference_name = None - frappe.form_dict.like = None - frappe.local.request_ip = None - - def test_feedback_creation_updation(self): - from frappe.website.doctype.blog_post.test_blog_post import make_test_blog - - test_blog = make_test_blog() - - frappe.db.delete("Feedback", {"reference_doctype": "Blog Post"}) - - from frappe.templates.includes.feedback.feedback import give_feedback - - frappe.form_dict.reference_doctype = "Blog Post" - frappe.form_dict.reference_name = test_blog.name - frappe.form_dict.like = True - frappe.local.request_ip = "127.0.0.1" - - feedback = give_feedback() - - self.assertEqual(feedback.like, True) - - frappe.form_dict.like = False - - updated_feedback = give_feedback() - - self.assertEqual(updated_feedback.like, False) - - frappe.db.delete("Feedback", {"reference_doctype": "Blog Post"}) - - test_blog.delete() diff --git a/frappe/patches.txt b/frappe/patches.txt index 425468f06c..d9b827931c 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -192,6 +192,7 @@ frappe.patches.v14_0.reset_creation_datetime frappe.patches.v14_0.remove_is_first_startup frappe.patches.v14_0.clear_long_pending_stale_logs frappe.patches.v14_0.log_settings_migration +frappe.patches.v14_0.setup_likes_from_feedback [post_model_sync] frappe.patches.v14_0.drop_data_import_legacy diff --git a/frappe/patches/v14_0/setup_likes_from_feedback.py b/frappe/patches/v14_0/setup_likes_from_feedback.py new file mode 100644 index 0000000000..d88f69ce4b --- /dev/null +++ b/frappe/patches/v14_0/setup_likes_from_feedback.py @@ -0,0 +1,30 @@ +import frappe + + +def execute(): + frappe.reload_doctype("Comment") + + if frappe.db.count("Feedback") > 20000: + frappe.db.auto_commit_on_many_writes = True + + for feedback in frappe.get_all("Feedback", fields=["*"]): + if feedback.like: + new_comment = frappe.new_doc("Comment") + new_comment.comment_type = "Like" + new_comment.comment_email = feedback.owner + new_comment.content = "Liked by: " + feedback.owner + new_comment.reference_doctype = feedback.reference_doctype + new_comment.reference_name = feedback.reference_name + new_comment.creation = feedback.creation + new_comment.modified = feedback.modified + new_comment.owner = feedback.owner + new_comment.modified_by = feedback.modified_by + new_comment.ip_address = feedback.ip_address + new_comment.db_insert() + + if frappe.db.auto_commit_on_many_writes: + frappe.db.auto_commit_on_many_writes = False + + # clean up + frappe.db.delete("Feedback") + frappe.db.commit() diff --git a/frappe/templates/includes/comments/comment.html b/frappe/templates/includes/comments/comment.html index 4713ee498d..64de9e5943 100644 --- a/frappe/templates/includes/comments/comment.html +++ b/frappe/templates/includes/comments/comment.html @@ -13,6 +13,6 @@ {{ frappe.utils.pretty_date(comment.creation) }} -
{{ frappe.utils.strip_html(comment.content) | markdown }}
+
{{ frappe.utils.strip_html(comment.content) | markdown }}
\ No newline at end of file diff --git a/frappe/templates/includes/comments/comments.html b/frappe/templates/includes/comments/comments.html index 0007f56934..63ec6a21bd 100644 --- a/frappe/templates/includes/comments/comments.html +++ b/frappe/templates/includes/comments/comments.html @@ -57,7 +57,7 @@ {% endblock %} diff --git a/frappe/website/doctype/blog_post/test_blog_post.py b/frappe/website/doctype/blog_post/test_blog_post.py index d202d15642..3ea447d90c 100644 --- a/frappe/website/doctype/blog_post/test_blog_post.py +++ b/frappe/website/doctype/blog_post/test_blog_post.py @@ -152,6 +152,29 @@ class TestBlogPost(FrappeTestCase): frappe.delete_doc("Blog Post", blog.name) frappe.delete_doc("Blog Category", blog.blog_category) + def test_like_dislike(self): + test_blog = make_test_blog() + + frappe.db.delete("Comment", {"comment_type": "Like", "reference_doctype": "Blog Post"}) + + from frappe.templates.includes.likes.likes import like + + frappe.form_dict.reference_doctype = "Blog Post" + frappe.form_dict.reference_name = test_blog.name + frappe.form_dict.like = True + frappe.local.request_ip = "127.0.0.1" + + liked = like() + self.assertEqual(liked, True) + + frappe.form_dict.like = False + + disliked = like() + self.assertEqual(disliked, False) + + frappe.db.delete("Comment", {"comment_type": "Like", "reference_doctype": "Blog Post"}) + test_blog.delete() + def scrub(text): return WebsiteGenerator.scrub(None, text) diff --git a/frappe/website/doctype/blog_settings/blog_settings.json b/frappe/website/doctype/blog_settings/blog_settings.json index aed1e77969..4e89af5c8e 100644 --- a/frappe/website/doctype/blog_settings/blog_settings.json +++ b/frappe/website/doctype/blog_settings/blog_settings.json @@ -19,7 +19,7 @@ "cta_label", "cta_url", "section_break_12", - "feedback_limit", + "like_limit", "column_break_14", "comment_limit" ], @@ -89,13 +89,6 @@ "fieldname": "section_break_12", "fieldtype": "Section Break" }, - { - "default": "5", - "description": "Feedback limit per hour", - "fieldname": "feedback_limit", - "fieldtype": "Int", - "label": "Feedback limit" - }, { "default": "5", "description": "Comment limit per hour", @@ -118,13 +111,20 @@ "fieldname": "browse_by_category", "fieldtype": "Check", "label": "Browse by category" + }, + { + "default": "5", + "description": "Like limit per hour", + "fieldname": "like_limit", + "fieldtype": "Int", + "label": "Like limit" } ], "icon": "fa fa-cog", "idx": 1, "issingle": 1, "links": [], - "modified": "2021-12-20 13:40:32.312459", + "modified": "2022-07-12 17:45:49.108398", "modified_by": "Administrator", "module": "Website", "name": "Blog Settings", diff --git a/frappe/website/doctype/blog_settings/blog_settings.py b/frappe/website/doctype/blog_settings/blog_settings.py index ed22f64fd7..6b1d7b6323 100644 --- a/frappe/website/doctype/blog_settings/blog_settings.py +++ b/frappe/website/doctype/blog_settings/blog_settings.py @@ -15,8 +15,8 @@ class BlogSettings(Document): clear_cache("writers") -def get_feedback_limit(): - return frappe.db.get_single_value("Blog Settings", "feedback_limit") or 5 +def get_like_limit(): + return frappe.db.get_single_value("Blog Settings", "like_limit") or 5 def get_comment_limit(): From 0a41c4051c2f8bb63bce2b11f45cf105200f0daf Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 14 Jul 2022 18:01:47 +0530 Subject: [PATCH 07/23] fix: Do not relay email to standard users Co-authored-by: Ritwik Puri --- frappe/core/doctype/communication/mixins.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/communication/mixins.py b/frappe/core/doctype/communication/mixins.py index 695b8bebae..af3b0a4661 100644 --- a/frappe/core/doctype/communication/mixins.py +++ b/frappe/core/doctype/communication/mixins.py @@ -73,7 +73,8 @@ class CommunicationEmailMixin: if include_sender: cc.append(self.sender_mailid) if is_inbound_mail_communcation: - cc.append(self.get_owner()) + if (doc_owner := self.get_owner()) not in frappe.STANDARD_USERS: + cc.append(doc_owner) cc = set(cc) - {self.sender_mailid} cc.update(self.get_assignees()) From 1f0e019e89a887bb14c59d3566b9fdd9d4659b2b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 14 Jul 2022 19:02:19 +0530 Subject: [PATCH 08/23] fix(UX): correct message for empty prepared report (#17517) --- frappe/public/js/frappe/views/reports/query_report.js | 3 ++- 1 file changed, 2 insertions(+), 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 80b251e5ec..e15cc339ae 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -623,6 +623,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { if (data.prepared_report) { this.prepared_report = true; + this.prepared_report_document = data.doc // If query_string contains prepared_report_name then set filters // to match the mentioned prepared report doc and disable editing if (query_params.prepared_report_name) { @@ -1800,7 +1801,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { } toggle_nothing_to_show(flag) { - let message = this.prepared_report + let message = (this.prepared_report && !this.prepared_report_document) ? __('This is a background report. Please set the appropriate filters and then generate a new one.') : this.get_no_result_message(); From c200f5b3ae8431d03ccdf18c0c3f53dd8782f2dd Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 15 Jul 2022 11:59:04 +0530 Subject: [PATCH 09/23] ci: check build requirement before setting up python [skip ci] --- .github/workflows/patch-mariadb-tests.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/patch-mariadb-tests.yml b/.github/workflows/patch-mariadb-tests.yml index 73e0dda5de..1e21ae8549 100644 --- a/.github/workflows/patch-mariadb-tests.yml +++ b/.github/workflows/patch-mariadb-tests.yml @@ -30,26 +30,28 @@ jobs: - name: Clone uses: actions/checkout@v3 + - name: Check if build should be run + id: check-build + run: | + python "${GITHUB_WORKSPACE}/.github/helper/roulette.py" + env: + TYPE: "server" + PR_NUMBER: ${{ github.event.number }} + REPO_NAME: ${{ github.repository }} + - name: Setup Python + if: ${{ steps.check-build.outputs.build == 'strawberry' }} uses: "gabrielfalcao/pyenv-action@v10" with: versions: 3.10:latest, 3.7:latest - name: Setup Node + if: ${{ steps.check-build.outputs.build == 'strawberry' }} uses: actions/setup-node@v3 with: node-version: 14 check-latest: true - - name: Check if build should be run - id: check-build - run: | - python "${GITHUB_WORKSPACE}/.github/helper/roulette.py" - env: - TYPE: "server" - PR_NUMBER: ${{ github.event.number }} - REPO_NAME: ${{ github.repository }} - - name: Add to Hosts if: ${{ steps.check-build.outputs.build == 'strawberry' }} run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts From ddbbc0ef8df16f57a921f2e0f2c634535448bd80 Mon Sep 17 00:00:00 2001 From: phot0n Date: Fri, 15 Jul 2022 14:23:05 +0530 Subject: [PATCH 10/23] fix: add default system manager role when changing from child to non-child table doctype --- frappe/core/doctype/doctype/doctype.js | 12 +++++++++--- frappe/core/doctype/doctype/doctype.py | 7 +++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.js b/frappe/core/doctype/doctype/doctype.js index 514e3a9455..3a9b1f63dc 100644 --- a/frappe/core/doctype/doctype/doctype.js +++ b/frappe/core/doctype/doctype/doctype.js @@ -46,9 +46,7 @@ frappe.ui.form.on('DocType', { } if(frm.is_new()) { - if (!(frm.doc.permissions && frm.doc.permissions.length)) { - frm.add_child('permissions', {role: 'System Manager'}); - } + frm.events.set_default_permission(frm); } else { frm.toggle_enable("engine", 0); } @@ -65,6 +63,14 @@ frappe.ui.form.on('DocType', { if (frm.doc.istable && frm.is_new()) { frm.set_value('autoname', 'autoincrement'); frm.set_value('allow_rename', 0); + } else if (!frm.doc.istable && !frm.is_new()) { + frm.events.set_default_permission(frm); + } + }, + + set_default_permission: (frm) => { + if (!(frm.doc.permissions && frm.doc.permissions.length)) { + frm.add_child('permissions', {role: 'System Manager'}); } }, }); diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index dbbbbc521a..2b28373384 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -181,10 +181,6 @@ class DocType(Document): ) ) - def after_insert(self): - # clear user cache so that on the next reload this doctype is included in boot - clear_user_cache(frappe.session.user) - def set_defaults_for_single_and_table(self): if self.issingle: self.allow_import = 0 @@ -412,6 +408,9 @@ class DocType(Document): delete_notification_count_for(doctype=self.name) frappe.clear_cache(doctype=self.name) + # clear user cache so that on the next reload this doctype is included in boot + clear_user_cache(frappe.session.user) + if not frappe.flags.in_install and hasattr(self, "before_update"): self.sync_global_search() From 5738676b461128d77c016c7125ff0bceb2d007ca Mon Sep 17 00:00:00 2001 From: phot0n Date: Fri, 15 Jul 2022 19:23:59 +0530 Subject: [PATCH 11/23] fix: use on_update hook instead of after_save and after_insert after_save hook doesn;t exist so using that triggers nothing --- frappe/hooks.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index a337d8e0d3..66820ecd0f 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -180,12 +180,10 @@ doc_events = { "on_update": "frappe.integrations.doctype.google_contacts.google_contacts.update_contacts_to_google_contacts", }, "DocType": { - "after_insert": "frappe.cache_manager.build_domain_restriced_doctype_cache", - "after_save": "frappe.cache_manager.build_domain_restriced_doctype_cache", + "on_update": "frappe.cache_manager.build_domain_restriced_doctype_cache", }, "Page": { - "after_insert": "frappe.cache_manager.build_domain_restriced_page_cache", - "after_save": "frappe.cache_manager.build_domain_restriced_page_cache", + "on_update": "frappe.cache_manager.build_domain_restriced_page_cache", }, } From 454766c26379d36ecf3c7cfe7b30fcdc9b6e8a34 Mon Sep 17 00:00:00 2001 From: Amin Ahmed Date: Fri, 15 Jul 2022 21:17:34 +0300 Subject: [PATCH 12/23] Update datepicker_i18n.js --- frappe/public/js/frappe/form/controls/datepicker_i18n.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/datepicker_i18n.js b/frappe/public/js/frappe/form/controls/datepicker_i18n.js index f010325c2e..a5b825072d 100644 --- a/frappe/public/js/frappe/form/controls/datepicker_i18n.js +++ b/frappe/public/js/frappe/form/controls/datepicker_i18n.js @@ -22,10 +22,10 @@ import "air-datepicker/dist/js/i18n/datepicker.zh.js"; months: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر'], monthsShort: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر'], today: 'اليوم', - clear: 'Clear', + clear: 'حذف', dateFormat: 'dd/mm/yyyy', timeFormat: 'hh:ii aa', - firstDay: 0 + firstDay: 6 }; })(jQuery); From 55fb8acafa3e63d2982850331f5cd8c6976d937d Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 17 Jul 2022 20:07:05 +0530 Subject: [PATCH 13/23] perf(DX): add watchdog as developer dependency Werkzeug reloader is right now using an inefficient `stat` based reloader which is horrible on large codebases with low-powered devices. Difference: - `stat` based reloader basically checks each and every file if they have changed or not. - watchdog subscribes to platform specific change events on kernel (like kqueue, fsevents or inotify ) --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index a1706ac33e..5eeb6f46dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,3 +109,4 @@ coverage = "~=6.4.1" Faker = "~=13.12.1" pyngrok = "~=5.0.5" unittest-xml-reporting = "~=3.0.4" +watchdog = "~=2.1.9" From 29c855b02807107813676bc4c2db49e4944462a0 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 18 Jul 2022 15:10:49 +0530 Subject: [PATCH 14/23] fix: db.get_value -> db.get_single_value (#17531) db.get_value for singles returns string type always, this is confusing behaviour, db.get_single_value should be used instead. semgrep rule: https://github.com/frappe/semgrep-rules/pull/16 --- .../core/doctype/sms_settings/sms_settings.py | 2 +- .../system_settings/system_settings.py | 2 +- frappe/core/doctype/user/user.py | 6 ++--- .../dropbox_settings/dropbox_settings.py | 6 ++--- .../doctype/google_drive/google_drive.py | 2 +- .../oauth_provider_settings.py | 4 +++- .../s3_backup_settings/s3_backup_settings.py | 4 ++-- .../patches/v11_0/set_dropbox_file_backup.py | 2 +- .../pages/integrations/razorpay_checkout.py | 2 +- frappe/twofactor.py | 22 ++++++++----------- frappe/utils/data.py | 2 +- .../doctype/web_page_view/web_page_view.py | 2 +- .../website_settings/google_indexing.py | 2 +- frappe/www/contact.py | 2 +- 14 files changed, 29 insertions(+), 31 deletions(-) diff --git a/frappe/core/doctype/sms_settings/sms_settings.py b/frappe/core/doctype/sms_settings/sms_settings.py index 686890514a..0a5536eb9b 100644 --- a/frappe/core/doctype/sms_settings/sms_settings.py +++ b/frappe/core/doctype/sms_settings/sms_settings.py @@ -63,7 +63,7 @@ def send_sms(receiver_list, msg, sender_name="", success_msg=True): "success_msg": success_msg, } - if frappe.db.get_value("SMS Settings", None, "sms_gateway_url"): + if frappe.db.get_single_value("SMS Settings", "sms_gateway_url"): send_via_gateway(arg) else: msgprint(_("Please Update SMS Settings")) diff --git a/frappe/core/doctype/system_settings/system_settings.py b/frappe/core/doctype/system_settings/system_settings.py index e4d36b7fc7..fbdc188742 100644 --- a/frappe/core/doctype/system_settings/system_settings.py +++ b/frappe/core/doctype/system_settings/system_settings.py @@ -28,7 +28,7 @@ class SystemSettings(Document): if self.enable_two_factor_auth: if self.two_factor_method == "SMS": - if not frappe.db.get_value("SMS Settings", None, "sms_gateway_url"): + if not frappe.db.get_single_value("SMS Settings", "sms_gateway_url"): frappe.throw( _("Please setup SMS before setting it as an authentication method, via SMS Settings") ) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 12a48afe7e..6d0de186a5 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -611,10 +611,10 @@ class User(Document): """ login_with_mobile = cint( - frappe.db.get_value("System Settings", "System Settings", "allow_login_using_mobile_number") + frappe.db.get_single_value("System Settings", "allow_login_using_mobile_number") ) login_with_username = cint( - frappe.db.get_value("System Settings", "System Settings", "allow_login_using_user_name") + frappe.db.get_single_value("System Settings", "allow_login_using_user_name") ) or_filters = [{"name": user_name}] @@ -861,7 +861,7 @@ def sign_up(email, full_name, redirect_to): user.insert() # set default signup role as per Portal Settings - default_role = frappe.db.get_value("Portal Settings", None, "default_role") + default_role = frappe.db.get_single_value("Portal Settings", "default_role") if default_role: user.add_roles(default_role) diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py index 50c5fa8fe6..dc9db2ccda 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py @@ -62,21 +62,21 @@ def take_backups_weekly(): def take_backups_if(freq): - if frappe.db.get_value("Dropbox Settings", None, "backup_frequency") == freq: + if frappe.db.get_single_value("Dropbox Settings", "backup_frequency") == freq: take_backup_to_dropbox() def take_backup_to_dropbox(retry_count=0, upload_db_backup=True): did_not_upload, error_log = [], [] try: - if cint(frappe.db.get_value("Dropbox Settings", None, "enabled")): + if cint(frappe.db.get_single_value("Dropbox Settings", "enabled")): validate_file_size() did_not_upload, error_log = backup_to_dropbox(upload_db_backup) if did_not_upload: raise Exception - if cint(frappe.db.get_value("Dropbox Settings", None, "send_email_for_successful_backup")): + if cint(frappe.db.get_single_value("Dropbox Settings", "send_email_for_successful_backup")): send_email(True, "Dropbox", "Dropbox Settings", "send_notifications_to") except JobTimeoutException: if retry_count < 2: diff --git a/frappe/integrations/doctype/google_drive/google_drive.py b/frappe/integrations/doctype/google_drive/google_drive.py index 62100ae7c5..c24d797086 100644 --- a/frappe/integrations/doctype/google_drive/google_drive.py +++ b/frappe/integrations/doctype/google_drive/google_drive.py @@ -48,7 +48,7 @@ def authorize_access(reauthorize=False, code=None): """ oauth_code = ( - frappe.db.get_value("Google Drive", "Google Drive", "authorization_code") if not code else code + frappe.db.get_single_value("Google Drive", "authorization_code") if not code else code ) oauth_obj = GoogleOAuth("drive") diff --git a/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py b/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py index 984382df9d..5a918db587 100644 --- a/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py +++ b/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py @@ -14,7 +14,9 @@ def get_oauth_settings(): """Returns oauth settings""" out = frappe._dict( { - "skip_authorization": frappe.db.get_value("OAuth Provider Settings", None, "skip_authorization") + "skip_authorization": frappe.db.get_single_value( + "OAuth Provider Settings", "skip_authorization" + ) } ) diff --git a/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py b/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py index 1c2d39be10..568ff71b00 100755 --- a/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py +++ b/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py @@ -76,8 +76,8 @@ def take_backups_monthly(): def take_backups_if(freq): - if cint(frappe.db.get_value("S3 Backup Settings", None, "enabled")): - if frappe.db.get_value("S3 Backup Settings", None, "frequency") == freq: + if cint(frappe.db.get_single_value("S3 Backup Settings", "enabled")): + if frappe.db.get_single_value("S3 Backup Settings", "frequency") == freq: take_backups_s3() diff --git a/frappe/patches/v11_0/set_dropbox_file_backup.py b/frappe/patches/v11_0/set_dropbox_file_backup.py index c9dec31414..396491e8b3 100644 --- a/frappe/patches/v11_0/set_dropbox_file_backup.py +++ b/frappe/patches/v11_0/set_dropbox_file_backup.py @@ -4,6 +4,6 @@ from frappe.utils import cint def execute(): frappe.reload_doctype("Dropbox Settings") - check_dropbox_enabled = cint(frappe.db.get_value("Dropbox Settings", None, "enabled")) + check_dropbox_enabled = cint(frappe.db.get_single_value("Dropbox Settings", "enabled")) if check_dropbox_enabled == 1: frappe.db.set_value("Dropbox Settings", None, "file_backup", 1) diff --git a/frappe/templates/pages/integrations/razorpay_checkout.py b/frappe/templates/pages/integrations/razorpay_checkout.py index b4f9e74a03..d0e77f6d8a 100644 --- a/frappe/templates/pages/integrations/razorpay_checkout.py +++ b/frappe/templates/pages/integrations/razorpay_checkout.py @@ -51,7 +51,7 @@ def get_context(context): def get_api_key(): - api_key = frappe.db.get_value("Razorpay Settings", None, "api_key") + api_key = frappe.db.get_single_value("Razorpay Settings", "api_key") if cint(frappe.form_dict.get("use_sandbox")): api_key = frappe.conf.sandbox_api_key diff --git a/frappe/twofactor.py b/frappe/twofactor.py index 26fc3ad619..528e7f8c8b 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -27,10 +27,10 @@ def toggle_two_factor_auth(state, roles=None): def two_factor_is_enabled(user=None): """Returns True if 2FA is enabled.""" - enabled = int(frappe.db.get_value("System Settings", None, "enable_two_factor_auth") or 0) + enabled = int(frappe.db.get_single_value("System Settings", "enable_two_factor_auth") or 0) if enabled: bypass_two_factor_auth = int( - frappe.db.get_value("System Settings", None, "bypass_2fa_for_retricted_ip_users") or 0 + frappe.db.get_single_value("System Settings", "bypass_2fa_for_retricted_ip_users") or 0 ) if bypass_two_factor_auth and user: user_doc = frappe.get_doc("User", user) @@ -127,7 +127,7 @@ def get_otpsecret_for_(user): def get_verification_method(): - return frappe.db.get_value("System Settings", None, "two_factor_method") + return frappe.db.get_single_value("System Settings", "two_factor_method") def confirm_otp_token(login_manager, otp=None, tmp_id=None): @@ -173,7 +173,7 @@ def confirm_otp_token(login_manager, otp=None, tmp_id=None): def get_verification_obj(user, token, otp_secret): - otp_issuer = frappe.db.get_value("System Settings", "System Settings", "otp_issuer_name") + otp_issuer = frappe.db.get_single_value("System Settings", "otp_issuer_name") verification_method = get_verification_method() verification_obj = None if verification_method == "SMS": @@ -249,7 +249,7 @@ def process_2fa_for_email(user, token, otp_secret, otp_issuer, method="Email"): def get_email_subject_for_2fa(kwargs_dict): """Get email subject for 2fa.""" subject_template = _("Login Verification Code from {}").format( - frappe.db.get_value("System Settings", "System Settings", "otp_issuer_name") + frappe.db.get_single_value("System Settings", "otp_issuer_name") ) subject = frappe.render_template(subject_template, kwargs_dict) return subject @@ -269,7 +269,7 @@ def get_email_body_for_2fa(kwargs_dict): def get_email_subject_for_qr_code(kwargs_dict): """Get QRCode email subject.""" subject_template = _("One Time Password (OTP) Registration Code from {}").format( - frappe.db.get_value("System Settings", "System Settings", "otp_issuer_name") + frappe.db.get_single_value("System Settings", "otp_issuer_name") ) subject = frappe.render_template(subject_template, kwargs_dict) return subject @@ -289,9 +289,7 @@ def get_link_for_qrcode(user, totp_uri): key = frappe.generate_hash(length=20) key_user = f"{key}_user" key_uri = f"{key}_uri" - lifespan = ( - int(frappe.db.get_value("System Settings", "System Settings", "lifespan_qrcode_image")) or 240 - ) + lifespan = int(frappe.db.get_single_value("System Settings", "lifespan_qrcode_image")) or 240 frappe.cache().set_value(key_uri, totp_uri, expires_in_sec=lifespan) frappe.cache().set_value(key_user, user, expires_in_sec=lifespan) return get_url(f"/qrcode?k={key}") @@ -447,9 +445,7 @@ def should_remove_barcode_image(barcode): """Check if it's time to delete barcode image from server.""" if isinstance(barcode, str): barcode = frappe.get_doc("File", barcode) - lifespan = ( - frappe.db.get_value("System Settings", "System Settings", "lifespan_qrcode_image") or 240 - ) + lifespan = frappe.db.get_single_value("System Settings", "lifespan_qrcode_image") or 240 if time_diff_in_seconds(get_datetime(), barcode.creation) > int(lifespan): return True return False @@ -464,7 +460,7 @@ def reset_otp_secret(user): if frappe.session.user != user: frappe.only_for("System Manager", message=True) - otp_issuer = frappe.db.get_value("System Settings", "System Settings", "otp_issuer_name") + otp_issuer = frappe.db.get_single_value("System Settings", "otp_issuer_name") user_email = frappe.db.get_value("User", user, "email") frappe.defaults.clear_default(user + "_otplogin") diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 81ca143682..8a970e57cc 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -1545,7 +1545,7 @@ def get_url(uri: str | None = None, full_address: bool = False) -> str: host_name = protocol + frappe.local.site else: - host_name = frappe.db.get_value("Website Settings", "Website Settings", "subdomain") + host_name = frappe.db.get_single_value("Website Settings", "subdomain") if not host_name: host_name = "http://localhost" diff --git a/frappe/website/doctype/web_page_view/web_page_view.py b/frappe/website/doctype/web_page_view/web_page_view.py index 7417f2d290..c3aef62584 100644 --- a/frappe/website/doctype/web_page_view/web_page_view.py +++ b/frappe/website/doctype/web_page_view/web_page_view.py @@ -49,4 +49,4 @@ def get_page_view_count(path): def is_tracking_enabled(): - return frappe.db.get_value("Website Settings", "Website Settings", "enable_view_tracking") + return frappe.db.get_single_value("Website Settings", "enable_view_tracking") diff --git a/frappe/website/doctype/website_settings/google_indexing.py b/frappe/website/doctype/website_settings/google_indexing.py index 4f67949f86..fbd5fa7820 100644 --- a/frappe/website/doctype/website_settings/google_indexing.py +++ b/frappe/website/doctype/website_settings/google_indexing.py @@ -16,7 +16,7 @@ def authorize_access(reauthorize=False, code=None): """If no Authorization code get it from Google and then request for Refresh Token.""" oauth_code = ( - frappe.db.get_value("Website Settings", "Website Settings", "indexing_authorization_code") + frappe.db.get_single_value("Website Settings", "indexing_authorization_code") if not code else code ) diff --git a/frappe/www/contact.py b/frappe/www/contact.py index 11be5e86da..cf26539ff4 100644 --- a/frappe/www/contact.py +++ b/frappe/www/contact.py @@ -51,7 +51,7 @@ def send_message(subject="Website Query", message="", sender=""): return # send email - forward_to_email = frappe.db.get_value("Contact Us Settings", None, "forward_to_email") + forward_to_email = frappe.db.get_single_value("Contact Us Settings", "forward_to_email") if forward_to_email: frappe.sendmail(recipients=forward_to_email, sender=sender, content=message, subject=subject) From b73899e99dbd7ca224c8ae4212322459abb20787 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 15 Jul 2022 19:56:15 +0530 Subject: [PATCH 15/23] feat: frappe.utils.debug.watch_property to debug JS This util adds a watcher on any JS object for purpose of debugging, whenever the property changes a console trace is generated. A custom callback function can also be passed if required. Usage: ```javascript filters = {} frappe.utils.debug.watch_property(filters, "company"); // any changes to company key on filters object from now on will print a console trace ``` only for debugging, make sure to not commit it in codebase! :) debug --- frappe/public/js/frappe/utils/utils.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 34374d7c85..877add95bf 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1537,4 +1537,29 @@ Object.assign(frappe.utils, { is_current_user(user) { return user === frappe.session.user; }, + + debug: { + watch_property(obj, prop, callback=console.trace) { + if (!frappe.boot.developer_mode) { + return; + } + console.warn("Adding property watcher, make sure to remove it after debugging."); + + // Adapted from https://stackoverflow.com/a/11658693 + // Reused under CC-BY-SA 4.0 + // changes: variable names are changed for consistency with our codebase + const private_prop = "$_" + prop + "_$"; + obj[private_prop] = obj[prop]; + + Object.defineProperty(obj, prop, { + get: function() { + return obj[private_prop]; + }, + set: function(value) { + callback(); + obj[private_prop] = value; + }, + }); + }, + } }); From 1a7a21bbe5a376084633b80aa412cbb3d8b760b4 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 15 Jul 2022 19:40:58 +0530 Subject: [PATCH 16/23] fix(UX)!: respect no filters set by user Currently if user resets a filter and comes back to same view default filters get populated. This is annoying behaviour especially since this is already saved in user setting. Fix: Always respect user's preference, if their last choice was no filters then load view without filters. --- frappe/public/js/frappe/list/base_list.js | 15 --------------- frappe/public/js/frappe/list/list_view.js | 5 +---- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index bbee90048b..e5272ccd91 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -764,10 +764,6 @@ class FilterArea { const doctype_fields = this.list_view.meta.fields; const title_field = this.list_view.meta.title_field; - const has_existing_filters = ( - this.list_view.filters - && this.list_view.filters.length > 0 - ); fields = fields.concat( doctype_fields @@ -803,23 +799,12 @@ class FilterArea { } } - let default_value; - - if (fieldtype === "Link" && !has_existing_filters) { - default_value = frappe.defaults.get_user_default(options); - } - - if (["__default", "__global"].includes(default_value)) { - default_value = null; - } - return { fieldtype: fieldtype, label: __(df.label), options: options, fieldname: df.fieldname, condition: condition, - default: default_value, onchange: () => this.refresh_list_view(), ignore_link_validation: fieldtype === "Dynamic Link", is_filter: 1, diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 94a3c29b27..cbeda50e53 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -87,10 +87,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { this.menu_items = this.menu_items.concat(this.get_menu_items()); // set filters from view_user_settings or list_settings - if ( - this.view_user_settings.filters && - this.view_user_settings.filters.length - ) { + if (Array.isArray(this.view_user_settings.filters)) { // Priority 1: view_user_settings const saved_filters = this.view_user_settings.filters; this.filters = this.validate_filters(saved_filters); From a98e47150f7f81ce4524e3e9d414d7ec4205f0d4 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 18 Jul 2022 16:26:00 +0530 Subject: [PATCH 17/23] feat(tiny): frappe.log -> frappe.log for server scripts This it already whitelisted but in global scope. [skip ci] --- frappe/utils/safe_exec.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py index 03f5d041ce..8e983f11b2 100644 --- a/frappe/utils/safe_exec.py +++ b/frappe/utils/safe_exec.py @@ -152,6 +152,7 @@ def get_safe_globals(): enqueue=safe_enqueue, sanitize_html=frappe.utils.sanitize_html, log_error=frappe.log_error, + log=frappe.log, db=NamespaceDict( get_list=frappe.get_list, get_all=frappe.get_all, From 59fff76cb34820d760d56b6b488e9a802dd2b308 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 18 Jul 2022 16:47:36 +0530 Subject: [PATCH 18/23] fix(dx): word wrap in script diffview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helpful for devs who write >120 character long code. 💩 [skip ci] --- frappe/public/js/frappe/utils/diffview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/utils/diffview.js b/frappe/public/js/frappe/utils/diffview.js index a898a318a1..a326fd74bc 100644 --- a/frappe/public/js/frappe/utils/diffview.js +++ b/frappe/public/js/frappe/utils/diffview.js @@ -89,7 +89,7 @@ frappe.ui.DiffView = class DiffView { } else if (line.startsWith("-")) { line_class = "delete"; } - html += `
${line}
`; + html += `
${line}
`; }); return `
${html}
`; } From 66c77f30dd0e03038dca559eeb3dd8fbb58117fb Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 15 Jul 2022 18:15:34 +0530 Subject: [PATCH 19/23] fix: chart wrapper padding This is close to the card boundary and looks ugly when numbers on Y axis start colliding with it. --- frappe/public/scss/desk/global.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/public/scss/desk/global.scss b/frappe/public/scss/desk/global.scss index 7466bdc874..1e68f374c4 100644 --- a/frappe/public/scss/desk/global.scss +++ b/frappe/public/scss/desk/global.scss @@ -589,6 +589,10 @@ details > summary:focus { background-color: var(--diff-removed); } +.chart-wrapper { + padding: 1em; +} + // REDESIGN TODO: Handling of broken images? // img.no-image:before { // .img-background(); From 3304e1c222a4a53d6e9cdcb7f7349221f3436978 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 18 Jul 2022 14:35:48 +0530 Subject: [PATCH 20/23] chore: bump frappe-charts to latest --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1685dc9b25..c4ba042a89 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "driver.js": "^0.9.8", "editorjs-undo": "0.1.6", "fast-deep-equal": "^2.0.1", - "frappe-charts": "^2.0.0-rc13", + "frappe-charts": "2.0.0-rc22", "frappe-datatable": "^1.16.4", "frappe-gantt": "^0.6.0", "highlight.js": "^10.4.1", diff --git a/yarn.lock b/yarn.lock index b80d101883..57d5a47131 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1256,10 +1256,10 @@ fraction.js@^4.1.2: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== -frappe-charts@^2.0.0-rc13: - version "2.0.0-rc13" - resolved "https://registry.yarnpkg.com/frappe-charts/-/frappe-charts-2.0.0-rc13.tgz#fdb251d7ae311c41e38f90a3ae108070ec6b9072" - integrity sha512-Bv7IfllIrjRbKWHn5b769dOSenqdBixAr6m5kurf8ZUOJSLOgK4HOXItJ7BA8n9PvviH9/k5DaloisjLM2Bm1w== +frappe-charts@^2.0.0-rc22: + version "2.0.0-rc22" + resolved "https://registry.yarnpkg.com/frappe-charts/-/frappe-charts-2.0.0-rc22.tgz#9a5a747febdc381a1d4d7af96e89cf519dfba8c0" + integrity sha512-N7f/8979wJCKjusOinaUYfMxB80YnfuVLrSkjpj4LtyqS0BGS6SuJxUnb7Jl4RWUFEIs7zEhideIKnyLeFZF4Q== frappe-datatable@^1.16.4: version "1.16.4" From 44630f5f62b75a58698f59c08686f7a1a2c17666 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 14 Jul 2022 20:11:58 +0530 Subject: [PATCH 21/23] feat: country specific number shortening in charts --- frappe/public/js/frappe/form/dashboard.js | 3 ++- frappe/public/js/frappe/utils/utils.js | 15 +++++++++++++-- .../js/frappe/views/reports/query_report.js | 4 ++-- .../js/frappe/views/reports/report_utils.js | 3 ++- .../public/js/frappe/views/reports/report_view.js | 3 ++- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index c057903a63..5c1b5d392f 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -554,7 +554,8 @@ frappe.ui.form.Dashboard = class FormDashboard { colors: ['green'], truncateLegends: 1, axisOptions: { - shortenYAxisNumbers: 1 + shortenYAxisNumbers: 1, + numberFormatter: frappe.utils.format_chart_axis_number, } }); this.show(); diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 877add95bf..78c9859b35 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1145,7 +1145,12 @@ Object.assign(frappe.utils, { { divisor: 1.0e+5, symbol: 'Lakh' - }], + }, + { + divisor: 1.0e+3, + symbol: 'K', + } + ], '': [{ divisor: 1.0e+12, @@ -1205,7 +1210,8 @@ Object.assign(frappe.utils, { axisOptions: { xIsSeries: 1, shortenYAxisNumbers: 1, - xAxisMode: 'tick' + xAxisMode: 'tick', + numberFormatter: frappe.utils.format_chart_axis_number, } }; @@ -1220,6 +1226,11 @@ Object.assign(frappe.utils, { return new frappe.Chart(wrapper, chart_args); }, + format_chart_axis_number(label, country) { + const default_country = frappe.sys_defaults.country; + return frappe.utils.shorten_number(label, country || default_country, 3); + }, + generate_route(item) { const type = item.type.toLowerCase(); if (type === "doctype") { diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index e15cc339ae..525bc5af4b 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -944,10 +944,10 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { }; } options.axisOptions = { - shortenYAxisNumbers: 1 + shortenYAxisNumbers: 1, + numberFormatter: frappe.utils.format_chart_axis_number, }; options.height = 280; - return options; } diff --git a/frappe/public/js/frappe/views/reports/report_utils.js b/frappe/public/js/frappe/views/reports/report_utils.js index f458a4daf6..35c8d132c8 100644 --- a/frappe/public/js/frappe/views/reports/report_utils.js +++ b/frappe/public/js/frappe/views/reports/report_utils.js @@ -30,7 +30,8 @@ frappe.report_utils = { colors: colors, axisOptions: { shortenYAxisNumbers: 1, - xAxisMode: 'tick' + xAxisMode: 'tick', + numberFormatter: frappe.utils.format_chart_axis_number, } }; diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 6880d472d3..2ea780c13d 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -529,7 +529,8 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { truncateLegends: 1, colors: ['#70E078', 'light-blue', 'orange', 'red'], axisOptions: { - shortenYAxisNumbers: 1 + shortenYAxisNumbers: 1, + numberFormatter: frappe.utils.format_chart_axis_number, }, tooltipOptions: { formatTooltipY: value => frappe.format(value, get_df(this.chart_args.y_axes[0]), { always_show_decimals: true, inline: true }, get_doc(value.doc)) From dcbf320b8b75496e56e4b72f889ddd169ade8693 Mon Sep 17 00:00:00 2001 From: Vladislav Date: Mon, 18 Jul 2022 16:14:35 +0300 Subject: [PATCH 22/23] fix: update ru translation (#17512) --- frappe/translations/ru.csv | 291 ++++++++++++++++++------------------- 1 file changed, 138 insertions(+), 153 deletions(-) diff --git a/frappe/translations/ru.csv b/frappe/translations/ru.csv index 5e333c8e9d..bcd02baf93 100644 --- a/frappe/translations/ru.csv +++ b/frappe/translations/ru.csv @@ -107,7 +107,7 @@ Hourly,Почасовой, Hub Sync ID,Идентификатор синхронизации концентратора, IP Address,IP адрес, Image,Изображение, -Image View,Просмотр изображения, +Image View,Просмотр изображений, Import Data,Импорт данных, Import Log,Лог импорта, Inactive,Неактивный, @@ -246,7 +246,7 @@ Start Import,Начать импорт, State,Состояние, Stopped,Приостановлено, Subject,Тема, -Submit,Провести, +Submit,Подписать, Successful,Успешно, Summary,Резюме, Sunday,Воскресенье, @@ -445,7 +445,7 @@ Append To can be one of {0},Добавить к может быть одним Append To is mandatory for incoming mails,Добавить к является обязательным для входящих сообщений, "Append as communication against this DocType (must have fields, ""Status"", ""Subject"")","Добавить как коммуникацию для этого DocType (должен иметь поля, ""Статус"", ""Тема"")", Applicable Document Types,Применимые типы документов, -Apply,Подать заявление, +Apply,Применить, Apply Strict User Permissions,Применение строгих пользовательских разрешений, Apply To All Document Types,Применить ко всем типам документов, Apply this rule if the User is the Owner,"Применить это правило, если пользователь является владелец", @@ -679,8 +679,8 @@ Client Information,Информация о клиенте, Client Script,Скрипт клиента, Client URLs,URL-адреса клиентов, Client side script extensions in Javascript,Расширения клиентский сценарий в Javascript, -Collapsible,Складной, -Collapsible Depends On,Складные Зависит от, +Collapsible,Сворачиваемый, +Collapsible Depends On,Сворачиваемый - зависит от, Column,Колонка, Column {0} already exist.,Столбец {0} уже существует., Column Break,Разрыв столбца, @@ -706,7 +706,8 @@ Compiled Successfully,Успешно скомпилировано, Complete By,Завершить до, Complete Registration,Полная регистрация, Complete Setup,Завершение установки, -Completed By,Завершено, +Completed By,Завершил(а), +Completed On,Завершено, Compose Email,Написать письмо, Condition Detail,Детализация условий, Conditions,Условия, @@ -755,8 +756,6 @@ Created Custom Field {0} in {1},Дата создания настраиваем Created On,Дата создания, Criticism,Критика, Criticize,Критиковать, -Ctrl + Down,Ctrl + Down, -Ctrl + Up,Ctrl + Up, Ctrl+Enter to add comment,"Ctrl+Enter, чтобы добавить комментарий", Currency Name,Название валюты, Currency Precision,Точность валюты, @@ -879,7 +878,7 @@ Disable SMTP server authentication,Отключить аутентификаци Disable Sidebar Stats,Отключить статистику боковой панели, Disable Signup,Отключение Регистрация, Disable Standard Email Footer,Отключить стандартный нижний колонтитул электронной почты, -Discard,Отбросить, +Discard,Отменить, Display,Показать, Display Depends On,Показание зависит от, Do not allow user to change after set the first time,Не позволяйте пользователю изменять после установить в первый раз, @@ -1120,11 +1119,11 @@ First Transaction,Первая сделка, First data column must be blank.,Первая колонка данных должна быть пустой., First set the name and save the record.,Сначала задайте имя и сохраните запись., Flag,Флаг, -Float,Сплавы, -Float Precision,Float Precision, -Fold,Сложить, -Fold can not be at the end of the form,Fold не может быть в конце виде, -Fold must come before a Section Break,Сложите должны прийти до перерыва раздел, +Float,Дробное, +Float Precision,Плавающая точность, +Fold,Сворачиваемое, +Fold can not be at the end of the form,Сворачиваемое поле не может быть в конце формы, +Fold must come before a Section Break,Сворачиваемое должно идти до разрыва раздел, Folder,Папка, Folder name should not include '/' (slash),Имя папки не должно включать «/» (косая черта), Folder {0} is not empty,Папка {0} не пуста, @@ -1240,15 +1239,12 @@ Home Settings,Домашние настройки, Home/Test Folder 1,Главная/Тестовая Папка 1, Home/Test Folder 1/Test Folder 3,Главная/Тестовая Папка 1/Тестовая Папка 3, Home/Test Folder 2,Главная/Тестовая Папка 2, -Host,Host, -Hostname,Hostname, "How should this currency be formatted? If not set, will use system defaults","Как следует отображать числа в этой валюте? Если не указано, то будут использоваться системные значения", -I found these: ,Я нашел следующее:, +I found these: ,Я нашел это: , ID,ID, ID (name) of the entity whose property is to be set,"ID (имя) лица, имущество которого должно быть установлено", Icon will appear on the button,Иконка появится на кнопке, Identity Details,Сведения о личности, -Idx,Idx, "If Apply Strict User Permission is checked and User Permission is defined for a DocType for a User, then all the documents where value of the link is blank, will not be shown to that User","Если флажок Apply Strict User Permission установлен, а для пользователя DocType для пользователя задано разрешение пользователя, тогда все документы, где значение ссылки пустым, не будут показаны этому пользователю", If Checked workflow status will not override status in list view,"Если установлен флажок, статус процесса не будет отменять статус в журнале", If Owner,Если владелец, @@ -1303,7 +1299,7 @@ In Filter,В фильтрe, In Global Search,В глобальном поиске, In Grid View,В табличном виде, In Hours,В час, -In List View,В виде списка, +In List View,Отображать в списке, In Preview,В предварительном просмотре, In Reply To,В ответ на, In Standard Filter,В стандартный фильтр, @@ -1322,7 +1318,7 @@ Index,Индекс, Indicator,Индикатор, Info,Информация, Info:,Информация:, -Initial Sync Count,Первоначальная синхронизация Count, +Initial Sync Count,Первоначальная синхронизация, InnoDB,InnoDB, Insert Above,Вставить сверху, Insert After,Вставить после, @@ -1333,7 +1329,7 @@ Insert Column Before {0},Вставить столбец до {0}, Insert Style,Вставьте стиль, Insert new records,Вставить новые записи, Instructions Emailed,Инструкции отправлены по электронной почте, -Insufficient Permission for {0},Недостаточное разрешение для {0}, +Insufficient Permission for {0},Недостаточно прав для {0}, Int,Интервал, Integration Request,Интеграция заявки, Integration Request Service,Интеграция заявки на обслуживание, @@ -1374,33 +1370,30 @@ Invalid recipient address,Неверный адрес получателя, Invalid {0} condition,Недопустимое условие {0}, Inverse,Обратный, Is,Является, -Is Attachments Folder,Является папкой вложений, -Is Child Table,Является дочерней таблицей, +Is Attachments Folder,Это папка для вложений, +Is Child Table,Это дочерняя таблицей, Is Custom Field,Это нестандартное поле, Is First Startup,Первый запуск, -Is Folder,Папка, +Is Folder,Это папка, Is Global,Является глобальным, Is Globally Pinned,Глобально закреплено, Is Home Folder,Является корневой папкой, Is Mandatory Field,Является обязательным полем, Is Pinned,Прикреплено, -Is Primary Contact,Основной контакт, +Is Primary Contact,Это основной контакт, Is Private,Является приватным, -Is Published Field,Есть Опубликовано поле, -Is Published Field must be a valid fieldname,Опубликовано Поле должно быть действительным имя_полем, +Is Published Field,Это опубликованое поле, +Is Published Field must be a valid fieldname,Опубликованое роле должно быть допустимым именем поля, Is Single,Единственный, -Is Spam,Спам, -Is Standard,Стандартный отчёт, +Is Spam,Это спам, +Is Standard,Это стандартный отчёт, Is Submittable,Подлежит исполнению, Is Table,Является таблицей, Is Your Company Address,Является адресом вашей компании, It is risky to delete this file: {0}. Please contact your System Manager.,"Рискованно удалять этот файл: {0}. Пожалуйста, обратитесь к менеджеру системы.", Item cannot be added to its own descendents,Продукт не может быть добавлен к своим подпродуктам, -JS,JS, -JSON,JSON, JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Формат JavaScript: frappe.query_reports ['REPORTNAME'] = {}, Javascript to append to the head section of the page.,Javascript для добавления к головной части страницы., -Jinja,Jinja, John Doe,Джон Доу, Kanban,Канбан, Kanban Board Column,Колонка канбан-доски, @@ -1480,7 +1473,7 @@ List,Список, List Filter,Фильтр списка, List View Setting,Настройка просмотра списка, List a document type,Перечислите тип документа, -"List as [{""label"": _(""Jobs""), ""route"":""jobs""}]","Список как [{""Ярлык"": _(""Работы""), ""маршруты"":""работы""}]", +"List as [{""label"": _(""Jobs""), ""route"":""jobs""}]","Список как [{""Метка"": _(""Работы""), ""маршруты"":""работы""}]", List of backups available for download,"Список резервных копий, доступных для загрузки", List of patches executed,Список выполненных патчей, List of themes for Website.,Список тем для сайта., @@ -1513,7 +1506,7 @@ Long Text,Длинный текст, Looks like something is wrong with this site's Paypal configuration.,"Похоже, что что-то не так с конфигурацией Paypal этого сайта.", Looks like something is wrong with this site's payment gateway configuration. No payment has been made.,"Похоже, что-то не так с конфигурацией платежного шлюза этого сайта. Платеж не был выполнен.", "Looks like something went wrong during the transaction. Since we haven't confirmed the payment, Paypal will automatically refund you this amount. If it doesn't, please send us an email and mention the Correlation ID: {0}.","Похоже, что-то пошло не так во время транзакции. Поскольку мы не подтвердили платеж, Paypal автоматически вернет вам эту сумму. Если это не так, отправьте нам электронное письмо и укажите идентификатор корреляции: {0}.", -Madam,Госпожа, +Madam,Мадам, Main Section,Основной раздел, "Make ""name"" searchable in Global Search","Индексировать ""name"" для глобального поиска", Make use of longer keyboard patterns,Используйте более длинных моделей клавиатуры, @@ -1540,7 +1533,7 @@ Max Value,Макс. значение, Max width for type Currency is 100px in row {0},Макс. ширина для типа валюты 100px в строке {0}, Maximum Attachment Limit for this record reached.,Достигнут предел вложений для этой записи., Maximum {0} rows allowed,Макс. {0} строк разрешено, -"Meaning of Submit, Cancel, Amend","Значение Провести, Отменить, Изменить", +"Meaning of Submit, Cancel, Amend","Значение Подписать, Отменить, Изменить", Mention transaction completion page URL,URL-ссылка на страницу-упоминание о завершении транзакции, Mentions,Упоминания, Menu,Меню, @@ -1606,14 +1599,14 @@ New Chat,Новый чат, New Comment on {0}: {1},Новый комментарий к {0}: {1}, New Connection,Новое соединение, New Custom Print Format,Новый пользовательский печатный бланк, -New Email,Новая электронная почта, +New Email,Новое письмо, New Email Account,Новый аккаунт электронной почты, New Event,Новое событие, New Folder,Новая папка, New Kanban Board,Новая панель канбан, New Message from Website Contact Page,Новое сообщение с формы обратной связи на сайте, New Name,Новое имя, -New Newsletter,Новый бюллетень, +New Newsletter,Новая новость, New Password,Новый пароль, New Password Required.,Требуется новый пароль., New Print Format Name,Название нового печатного бланка, @@ -1672,8 +1665,8 @@ No template found at path: {0},Нет шаблона по адресу: {0}, No {0} found,{0} не найдено, No {0} mail,Нет {0} почта, No {0} permission,Нет {0} разрешение, -None: End of Workflow,Ни один: Конец потока, -Not Allowed: Disabled User,Не разрешено: отключен пользователь, +None: End of Workflow,Нет: конец рабочего процесса, +Not Allowed: Disabled User,Не разрешено: пользователь отключен, Not Ancestors Of,Не предки, Not Descendants Of,Не потомки, Not Equals,Не равно, @@ -1688,7 +1681,7 @@ Not a valid Comma Separated Value (CSV File),"Не является допуст Not a valid User Image.,Недействительный изображение пользователя., Not a valid Workflow Action,Недоступное действие рабочего-процесса, Not a valid user,Не является действительным пользователем, -Not a zip file,Не zip файл, +Not a zip file,Не является zip файлом, Not allowed for {0}: {1},Не разрешено для {0}: {1}, Not allowed for {0}: {1} in Row {2}. Restricted field: {3},Недопустимо для {0}: {1} в строке {2}. Запрещенное поле: {3}, Not allowed for {0}: {1}. Restricted field: {2},Не допускается для {0}: {1}. Запрещенное поле: {2}, @@ -1732,11 +1725,11 @@ OTP Secret has been reset. Re-registration will be required on next login.,OTP S OTP secret can only be reset by the Administrator.,Секрет OTP может быть сброшен администратором., Office,Офис, Office 365,Офис 365, -Old Password,Старый Пароль, -Old Password Required.,Требуется старый пароль., +Old Password,Старый пароль, +Old Password Required.,Старый пароль обязателен., Older backups will be automatically deleted,Более старые резервные копии будут автоматически удалены, "On {0}, {1} wrote:","На {0}, {1} писал:", -"Once submitted, submittable documents cannot be changed. They can only be Cancelled and Amended.",После отправки поданные документы не могут быть изменены. Они могут быть только отменены и исправлены., +"Once submitted, submittable documents cannot be changed. They can only be Cancelled and Amended.",После отправки подписанные документы не могут быть изменены. Они могут быть только отменены и исправлены., "Once you have set this, the users will only be able access documents (eg. Blog Post) where the link exists (eg. Blogger).","После такой установки, пользователи получат доступ только к документам (например, сообщениям в блоге), связанным с этими разрешениями пользователя (например, блоггера).", One Last Step,Последний шаг, One Time Password (OTP) Registration Code from {},Одноразовый пароль (OTP) Регистрационный код от {}, @@ -1760,7 +1753,7 @@ Open a dialog with mandatory fields to create a new record quickly,"Открой Open a module or tool,Открыть модуль или инструмент, Open your authentication app on your mobile phone.,Откройте приложение для проверки подлинности на своем мобильном телефоне., Open {0},Открыть {0}, -Opened,Открыт, +Opened,Открыть, Operator must be one of {0},Оператор должен быть одним из {0}, Option 1,Опция 1, Option 2,Опция 2, @@ -1778,9 +1771,7 @@ Org History Heading,Org История Заголовок, Orientation,Ориентация, Original Value,Первоначальная стоимость, Outgoing email account not correct,Исходящая учетная запись электронной почты не верна, -Outlook.com,Outlook.com, Output,Вывод, -PDF,PDF, PDF Page Size,Размер PDF страницы, PDF Settings,Настройки PDF, PDF generation failed,Не удалось сгенерировать PDF-файл, @@ -1790,17 +1781,17 @@ Page HTML,Страница HTML, Page Length,Длина страницы, Page Name,Имя страницы, Page Settings,Настройки страницы, -Page has expired!,Страница просрочена!, +Page has expired!,Срок действия страницы истек!, Page not found,Страница не найдена, Page to show on the website\n,Страница для показа на сайте, Pages in Desk (place holders),Страницы-заглушки, Parent,Родитель, Parent Error Snapshot,Родитель снимка ошибки, Parent Label,Родительская метка, -Parent Table,Родитель Таблица, +Parent Table,Родительская таблица, Parent is required to get child table data,Родитель обязан получать данные дочерней таблицы, Parent is the name of the document to which the data will get added to.,"Родитель - это имя документа, к которому будут добавлены данные.", -Partial Success,Частичный успех, +Partial Success,Выполнено не полностью, Partially Successful,Частично успешный, Participants,Участники, Passive,Пассивный, @@ -1903,14 +1894,14 @@ Please specify which date field must be checked,"Просьба уточнить Please specify which value field must be checked,"Просьба уточнить, какие значения поля должны быть проверены", Please try again,"Пожалуйста, попробуйте еще раз", Please verify your Email Address,"Пожалуйста, подтвердите свой адрес электронной почты", -Point Allocation Periodicity,Периодичность распределения точек, +Point Allocation Periodicity,Периодичность распределения баллов, Points,Баллы, Points Given,Баллы засчитаны, Port,Порт, Portal Menu,Меню портала, -Portal Menu Item,Портал Пункт меню, +Portal Menu Item,Пункт меню портала, Post,Опубликовать, -Post Comment,Оставьте комментарий, +Post Comment,Оставить комментарий, Postal,Почтовый, Postal Code,Почтовый индекс, Postprocess Method,Метод постпроцесса, @@ -1966,15 +1957,6 @@ Provider Name,Имя поставщика, Public Key,Открытый ключ, Publishable Key,Ключ для публикации, Published On,Опубликовано на, -Pull,Тянуть, -Pull Failed,Не удалось выполнить Pull, -Pull Insert,Вставить вкладыш, -Pull Update,Pull Update, -Push,От себя, -Push Delete,Нажмите Удалить, -Push Failed,Ошибка отправки, -Push Insert,Push Insert, -Push Update,Push Update, Python Module,Модуль Python, Pyver,Pyver, QR Code,QR код, @@ -1986,7 +1968,7 @@ Query,Запрос, Query Report,Отчёт-выборка, Query must be a SELECT,Запрос должен быть ВЫБОР, Queue should be one of {0},Очередь должна быть одной из {0}, -Queued for backup. It may take a few minutes to an hour.,Queued для резервного копирования. Это может занять несколько минут до часа., +Queued for backup. It may take a few minutes to an hour.,В очереди для резервного копирования. Это может занять от несколько минут до часа., Queued for backup. You will receive an email with the download link,Очередь для резервного копирования. Вы получите электронное письмо с ссылкой для загрузки, Quick Help for Setting Permissions,Быстрая помощь при настройки прав доступа, Rating: ,Рейтинг: , @@ -2091,8 +2073,8 @@ Retake,пересдавать, Retry,Повторить, Return to the Verification screen and enter the code displayed by your authentication app,"Вернитесь на экран проверки и введите код, отображаемый приложением для аутентификации.", Reverse Icon Color,Обратный цвет значка, -Revert,Вернуть, -Revert Of,Вернуть из, +Revert,Возврат, +Revert Of,Возвращенно из, Reverted,Отменено, Review Level,Уровень обзора, Review Levels,Уровни обзора, @@ -2101,9 +2083,8 @@ Reviews,Отзывы, Revoke,Аннулировать, Revoked,Аннулировано, Rich Text,Форматированный текст, -Robots.txt,Robots.txt, -Role Name,Имя роли, -Role Permission for Page and Report,Роль Разрешение на страницу и отчет, +Role Name,Название роли, +Role Permission for Page and Report,Разрешение роли для страницы и отчета, Role Permissions,Разрешения роли, Role Profile,Профиль ролей, Role and Level,Роль и уровень, @@ -2198,7 +2179,7 @@ Select Print Format,Выберите бланк для печати, Select Print Format to Edit,Выберите печатный бланк для редактирования, Select Role,Выберите роль, Select Table Columns for {0},Выберите столбцы таблицы для {0}, -Select Your Region,Выберите регион, +Select Your Region,Выберите ваш регион, Select a Brand Image first.,Выберите бренд изображение в первую очередь., Select a DocType to make a new format,"Выберите DOCTYPE, чтобы сделать новый бланк", Select a chat to start messaging.,"Выберите чат, чтобы начать обмен сообщениями.", @@ -2234,7 +2215,6 @@ Send only if there is any data,"Отправить только если ест Send unsubscribe message in email,Отправить сообщение об отказе от подписки на электронную почту, Sender,Отправитель, Sender Email,Электронная почта отправителя, -Sendgrid,Sendgrid, Sent Read Receipt,Отправлять уведомление о прочтении, Sent or Received,Отправлено или получено, Sent/Received Email,Отправлено/Получено письмо, @@ -2279,8 +2259,8 @@ Setup Reports to be emailed at regular intervals,Настройка регуля Share,Поделиться, Share URL,Поделиться URL, Share With,Поделиться с, -Share this document with,Поделитесь этот документ с, -Share {0} with,Поделиться {0}, +Share this document with,Поделиться этим документом с, +Share {0} with,Поделиться {0} с, Shared,Общий, Shared With,Совместно с, Shared with everyone,Общий для всех, @@ -2325,8 +2305,6 @@ Single Post (article).,Один пост(статья)., Single Types have only one record no tables associated. Values are stored in tabSingles,"Холост Типы нет только одна запись не таблицы, связанные. Значения сохраняются в tabSingles", Skip Authorization,Пропустить авторизацию, Skip rows with errors,Пропустить строки с ошибками, -Skype,Skype, -Slack,Slack, Slack Channel,Slack канал, Slack Webhook Error,Slack Webhook ошибка, Slack Webhook URL,Неверный URL веб-хостинга, @@ -2350,14 +2328,13 @@ Something went wrong while generating dropbox access token. Please check error l Sorry! I could not find what you were looking for.,"Извините! Я не мог найти то, что вы ищете.", Sorry! Sharing with Website User is prohibited.,Извините! Поделиться с сайта Пользователю запрещается., Sorry! User should have complete access to their own record.,Извините! Пользователь должен иметь полный доступ к своей записи., -Sorry! You are not permitted to view this page.,Извините! Вам не разрешается для просмотра этой страницы., +Sorry! You are not permitted to view this page.,Извините! У вас нет разрешений для просмотра этой страницы., "Sorry, you're not authorized.","Извините, вы не авторизованы.", Sort Field,Сортировать поле, Sort Order,Порядок сортировки, Sort field {0} must be a valid fieldname,Сортировка поля {0} должен быть действительным имя_поля, Source Text,Исходный текст, Spam,Спам, -SparkPost,SparkPost, Special Characters are not allowed,Спецсимволы не допустимы, "Standard DocType cannot have default print format, use Customize Form","Стандартный DocType не может иметь формат печати по умолчанию, используйте Настроить форму", Standard Print Format cannot be updated,Стандартный печатный бланк не может быть обновлен, @@ -2371,12 +2348,11 @@ Start Date Field,Поле начальной даты, Start a conversation.,Начните разговор., Start entering data below this line,Начните вводить данные ниже этой линии, Start new Format,Начать новую Формат, -StartTLS,StartTLS, Started,Начал, Starting Frappe ...,Запуск Frappé ..., Starts on,Начало, -States,Статусы, -"States for workflow (e.g. Draft, Approved, Cancelled).","Статусы бизнес-процесса (например: черновик, утверждён, отменён).", +States,Состояния, +"States for workflow (e.g. Draft, Approved, Cancelled).","Состояния рабочего-процесса (например: черновик, утверждён, отменён).", Static Parameters,Статические параметры, Stats based on last month's performance (from {0} to {1}),Статистика на основе результатов прошлого месяца (от {0} до {1}), Stats based on last week's performance (from {0} to {1}),Статистика на основе результатов прошлой недели (от {0} до {1}), @@ -2396,7 +2372,7 @@ Subdomain,Субдомен, Subject Field,Поле темы, Submit after importing,Отправить после импорта, Submit an Issue,Отправить вопрос, -Submit this document to confirm,Провести этот документ для подтверждения, +Submit this document to confirm,Подписать этот документ для подтверждения, Submit {0} documents?,Отправить {0} документы?, Submitting {0},Помещение {0}, Submitted Document cannot be converted back to draft. Transition row {0},Проведенный Документ не может быть преобразован обратно в проект. Переходная строка {0}, @@ -2437,8 +2413,6 @@ Team Members,Члены команды, Team Members Heading,Члены команды Возглавлять, Temporarily Disabled,Временно отключен, Test Email Address,Проверить адрес электронной почты, -Test Runner,Тест Runner, -Test_Folder,Test_Folder, Text,Текст, Text Align,Выравнивание текста, Text Color,Цвет текста, @@ -2463,8 +2437,8 @@ The system provides many pre-defined roles. You can add new roles to set finer p The user from this field will be rewarded points,Пользователь из этого поля будет вознагражден баллами, Theme,Тема, Theme URL,URL темы, -There can be only one Fold in a form,Там может быть только один Fold в виде, -There is an error in your Address Template {0},Существует ошибка в адресной Шаблон {0}, +There can be only one Fold in a form,В форме может быть только один Fold, +There is an error in your Address Template {0},Ошибка в вашем шаблоне адреса {0}, There is no data to be exported,Нет данных для экспорта, There is some problem with the file url: {0},Существует некоторая проблема с файловой URL: {0}, There must be atleast one permission rule.,Там должно быть по крайней мере один правило разрешения., @@ -2502,7 +2476,7 @@ This is similar to a commonly used password.,Это похоже на обычн This is the template file generated with only the rows having some error. You should use this file for correction and import.,"Это файл шаблона, сгенерированный только строками с некоторой ошибкой. Вы должны использовать этот файл для исправления и импорта.", This link has already been activated for verification.,Эта ссылка уже была активирована для проверки., This link is invalid or expired. Please make sure you have pasted correctly.,"Эта ссылка является недействительным или истек. Пожалуйста, убедитесь, что вы вставили правильно.", -This may get printed on multiple pages,Это может быть напечатано на нескольких страницах, +This may get printed on multiple pages,Это будет напечатано на нескольких страницах, This month,Этот месяц, This query style is discontinued,Этот стиль запроса прекращен, This report was generated on {0},Этот отчет был создан в {0}, @@ -2511,7 +2485,6 @@ This request has not yet been approved by the user.,Этот запрос еще This role update User Permissions for a user,Эта роль обновляет разрешения пользователя для пользователя, This will log out {0} from all other devices,Это выведет {0} из всех других устройств, This will permanently remove your data.,Это навсегда удалит ваши данные., -Throttled,Throttled, Thumbnail URL,Миниатюра URL, Time Interval,Интервал времени, Time Series,Временные ряды, @@ -2529,7 +2502,7 @@ Timeseries,Временные ряды, Timestamp,Временная отметка, Title Case,Название дела, Title Field,Название поля, -Title Prefix,Название Приставка, +Title Prefix,Название приставки, Title field must be a valid fieldname,Название поля должно быть допустимым имя_поля, To Date Field,Поле даты, To Do,Список дел, @@ -2589,7 +2562,7 @@ Type:,Тип:, UID,UID, UIDNEXT,UIDNEXT, UIDVALIDITY,UIDVALIDITY, -UNSEEN,НЕПРОЧИТАННО, +UNSEEN,НЕПРОЧИТАННЫЕ, UPPER CASE,ВЕРХНИЙ РЕГИСТР, "URIs for receiving authorization code once the user allows access, as well as failure responses. Typically a REST endpoint exposed by the Client App.\n
e.g. http://hostname//api/method/frappe.www.login.login_via_facebook","Идентификаторы URI для получения кода авторизации, как только пользователь разрешает доступ, а также ответы недостаточность. Как правило, конечная точка REST подвергается Клиентом App.
например, HTTP: //hostname//api/method/frappe.www.login.login_via_facebook", URLs,URL-адрес, @@ -2691,7 +2664,6 @@ Value for {0} cannot be a list,Значение {0} не может быть с Value missing for,Нет значения для, Value too big,Слишком большое значение, Values Changed,Значения изменено, -Verdana,Verdana, Verfication Code,Код проверки, Verification Link,Ссылка для проверки, Verification code has been sent to your registered email address.,Код подтверждения отправлен на ваш адрес электронной почты регистрации., @@ -2712,7 +2684,7 @@ View document,Просмотр документа, View report in your browser,Просмотр отчета в вашем браузере, View this in your browser,Просмотреть это в вашем браузере, View {0},Просмотреть {0}, -Viewed By,просмотрены, +Viewed By,Просмотрено, Visit,Посетите нас по адресу, Visitor,Посетитель, We have received a request for deletion of {0} data associated with: {1},"Мы получили запрос на удаление {0} данных, связанных с: {1}", @@ -2721,7 +2693,7 @@ Web Form,Веб форма, Web Form Field,Поле веб формы, Web Form Fields,Поля веб формы, Web Page,Веб-страница, -Web Page Link Text,Web Текст Ссылка на страницу, +Web Page Link Text,Текст ссылки веб-страницы, Web Site,Веб-сайт, Web View,Web View, Webhook,Webhook, @@ -2765,9 +2737,7 @@ Workflow state represents the current state of a document.,Состояние р Write,Написать, Wrong fieldname {0} in add_fetch configuration of custom script,Неверное имя поля {0} в конфигурации add_fetch пользовательского скрипта, X Axis Field,Поле оси X, -XLSX,XLSX, Y Axis Fields,Поля оси Y, -Yahoo Mail,Yahoo Mail, Yandex.Mail,Яндекс.Почта, Yesterday,Вчера, You are connected to internet.,Вы подключены к Интернету., @@ -2783,14 +2753,14 @@ You are not permitted to view the newsletter.,У Вас нет прав для You are now following this document. You will receive daily updates via email. You can change this in User Settings.,Вы подписаны на обновления данного документа. Вы будете получать ежедневные обновления по электронной почте. Вы можете изменить это в настройках пользователя., You can add dynamic properties from the document by using Jinja templating.,Вы можете добавить динамические свойства из документа с помощью шаблонов Jinja., You can also copy-paste this ,Вы также можете скопировать и вставить это , -"You can change Submitted documents by cancelling them and then, amending them.","Вы можете изменить Проведенные (Submitted) документы, отменив их, а затем изменив их.", +"You can change Submitted documents by cancelling them and then, amending them.","Вы можете изменить утвержденные документы, отменив их, а затем отредактировав.", You can find things by asking 'find orange in customers',Можно искать что-либо написав «найти апельсин у клиентов», You can only upload upto 5000 records in one go. (may be less in some cases),"Вы можете загружать одновременно до 5000 записей. (Возможно меньше, в некоторых случаях)", You can use Customize Form to set levels on fields.,Вы можете использовать Настройку формы (Customize Form) для установки уровней для полей., You can use wildcard %,Вы можете использовать подстановочные %, You can't set 'Options' for field {0},Нельзя включить «Опции» для поля {0}, You can't set 'Translatable' for field {0},Вы не можете установить «Переводимый» для поля {0}, -You cannot give review points to yourself,Вы не можете давать оценки себе, +You cannot give review points to yourself,Вы не можете не можете начислять себе баллы обзора, You cannot unset 'Read Only' for field {0},Нельзя отменить «только чтение» для поля {0}, You do not have enough permissions to access this resource. Please contact your manager to get access.,"У вас нет достаточных прав для доступа к этому ресурсу. Пожалуйста, обратитесь к своему менеджеру, чтобы получить доступ.", You do not have enough permissions to complete the action,У Вас нет достаточных прав для завершения действия, @@ -2811,13 +2781,13 @@ You need to be in developer mode to edit a Standard Web Form,Вы должны You need to be logged in and have System Manager Role to be able to access backups.,"Вы должны войти в систему (и иметь роль менеджера системы), чтобы иметь доступ к резервным копиям.", You need to be logged in to access this {0}.,"Вы должны войти, чтобы получить доступ к {0}.", "You need to have ""Share"" permission","Вы должны иметь разрешение ""Поделиться""", -You need write permission to rename,"Вам нужно письменное разрешение, чтобы переименовать", +You need write permission to rename,"Вам нужно разрешение на запись, чтобы переименовать", You selected Draft or Cancelled documents,Вы выбрали черновик или отмененные документы, You unfollowed this document,Вы отписались от этого документа, Your Country,Ваша страна, Your Language,Ваш язык, Your Name,Ваше имя, -Your account has been locked and will resume after {0} seconds,Ваша учетная запись заблокирована и возобновится после {0} секунд, +Your account has been locked and will resume after {0} seconds,Ваша учетная запись заблокирована и будет доступна через {0} секунд, Your connection request to Google Calendar was successfully accepted,Ваш запрос на подключение к Календарю Google был успешно принят, Your information has been submitted,Ваша информация была представлена, Your login id is,Ваш ID для авторизации, @@ -2830,28 +2800,26 @@ Your payment was successfully accepted,Ваш платёж был успешно "Your session has expired, please login again to continue.","Ваша сессия истекла, пожалуйста, войдите снова, чтобы продолжить.", Zero,Ноль, Zero means send records updated at anytime,При нуле обновленные записи отправляются в любое время, -_doctype,_doctype, -_report,_report, adjust,настроить, after_insert,после_вставки, -align-center,выровнять-центр, -align-justify,выровнять-оправдать, -align-left,выровнять левый, -align-right,выровнять правый, +align-center,выровнять-по-центру, +align-justify,выровнять-по-ширине, +align-left,выровнять-по-левой-стороне, +align-right,выровнять-по-правой-стороне, ap-northeast-1,ар-северо-восток-1, ap-northeast-2,ар-северо-восток-2, ap-northeast-3,ар-северо-восток-3, ap-south-1,ар-юго-1, ap-southeast-1,ар-юго-восток-1, ap-southeast-2,ар-юго-восток-2, -arrow-down,Стрелка вниз, -arrow-left,стрелка налево, -arrow-right,стрелка направо, -arrow-up,Стрелка вверх, +arrow-down,стрелка-вниз, +arrow-left,стрелка-налево, +arrow-right,стрелка-направо, +arrow-up,стрелка-вверх, asterisk,звёздочка, backward,назад, -ban-circle,Запрет круга, -bell,Накладная, +ban-circle,бан-кружок, +bell,колокольчик, bookmark,закладка, briefcase,портфель, bullhorn,рупор, @@ -2909,11 +2877,10 @@ gave {0} points,дал {0} баллов, gift,подарок, glass,стекло, globe,глобус, -hand-down,ручной вниз, -hand-left,ручной левый, -hand-right,ручной право, -hand-up,грабитель, -hdd,жесткий диск, +hand-down,рука-вниз, +hand-left,рука-влево, +hand-right,рука-вправо, +hand-up,рука-вверх, headphones,наушники, heart,сердце, hub,хаб, @@ -3011,7 +2978,7 @@ zoom-in,приблизить, zoom-out,отдалить, {0} Calendar,{0} Календарь, {0} Chart,{0} Диаграмма, -{0} Dashboard,{0} Панель инструментов, +{0} Dashboard,{0} Показатели, {0} List,{0} Список, {0} Modules,{0} Модули, {0} Report,{0} Отчет, @@ -3028,7 +2995,7 @@ zoom-out,отдалить, {0} appreciated {1},{0} признателен {1}, {0} appreciation point for {1} {2},{0} благодарность за {1} {2}, {0} appreciation points for {1} {2},{0} баллы за {1} {2}, -{0} assigned {1}: {2},{0} назначено {1}: {2}, +{0} assigned {1}: {2},{0} назначил(а) {1}: {2}, {0} cannot be set for Single types,{0} не может быть установлена для отдельных видов, {0} comments,{0} комментариев, {0} created successfully,{0} создано успешно, @@ -3053,7 +3020,7 @@ zoom-out,отдалить, {0} is not a valid Workflow State. Please update your Workflow and try again.,{0} не является допустимым состоянием рабочего процесса. Обновите свой рабочий процесс и повторите попытку., {0} is now default print format for {1} doctype,{0} — теперь формат печати по умолчанию для {1} doctype, {0} is saved,{0} сохранено, -{0} items selected,{0} продуктов выбрано, +{0} items selected,{0} элементов выбрано, {0} logged in,{0} авторизирован, {0} logged out: {1},{0} вышел: {1}, {0} minutes ago,{0} минут назад, @@ -3097,7 +3064,7 @@ zoom-out,отдалить, {0}: Cannot set Assign Submit if not Submittable,"{0}: Не удается установить Назначить проведение, если не подлежит проведению", {0}: Cannot set Cancel without Submit,{0}: Не удается установить Отмена без отправки, {0}: Cannot set Import without Create,{0}: Не удается установить Импорт без Создать, -"{0}: Cannot set Submit, Cancel, Amend without Write","{0}: Не удается выполнить Провести, Отменить, Изменить без Записать", +"{0}: Cannot set Submit, Cancel, Amend without Write","{0}: Не удается выполнить Подписать, Отменить, Изменить без Записать", {0}: Cannot set import as {1} is not importable,{0}: Не удается установить импорт как {1} не является ввозу, {0}: No basic permissions set,{0}: Не установлен базовый набор разрешений, "{0}: Only one rule allowed with the same Role, Level and {1}","{0}: только одно правило допускается для той же роли, уровня и {1}", @@ -3146,7 +3113,7 @@ About {0} seconds remaining,Осталось {0} секунд, Access Log,Журнал доступа, Access not allowed from this IP Address,Доступ с этого IP-адреса запрещен, Action Type,Тип действия, -Activity Log by ,Активность Журнал по, +Activity Log by ,Журнал активности по , Add Fields,Добавить поля, Administration,Администрирование, After Cancel,После отмены, @@ -3162,7 +3129,7 @@ Allow Auto Repeat,Разрешить автоматическое повторе Allow Google Calendar Access,Разрешить доступ к календарю Google, Allow Google Contacts Access,Разрешить доступ к контактам Google, Allow Google Drive Access,Разрешить доступ Google Drive, -Allow Guest,Разрешить гость, +Allow Guest,Разрешить гостя, Allow Guests to Upload Files,Разрешить гостям загружать файлы, Also adding the status dependency field {0},Также добавляем поле зависимости статуса {0}, An error occurred while setting Session Defaults,Произошла ошибка при настройке параметров сеанса по умолчанию, @@ -3216,8 +3183,8 @@ Click on the link below to approve the request,"Нажмите на ссылку Click on the lock icon to toggle public/private,"Нажмите на значок замка, чтобы переключить публичный / приватный", Click on {0} to generate Refresh Token.,"Нажмите {0}, чтобы сгенерировать токен обновления.", Close Condition,Закрыть условие, -Column {0},Столбец {0}, -Columns / Fields,Колонны / Поля, +Column {0},Колонка {0}, +Columns / Fields,Колонки / Поля, "Configure notifications for mentions, assignments, energy points and more.","Настройте уведомления для упоминаний, назначений, энергетических очков и многое другое.", Contact Email,Эл.почта для связи, Contact Numbers,Контактные номера, @@ -3234,8 +3201,7 @@ Could not create razorpay order,Не удалось создать заказ н Create Log,Создать журнал, Create your first {0},Создайте свой первый {0}, Created {0} records successfully.,Создано {0} записей успешно., -Cron,Cron, -Cron Format,Крон Формат, +Cron Format,Cron формат, Daily Events should finish on the Same Day.,Ежедневные события должны заканчиваться в тот же день., Daily Long,Ежедневно, Default Role on Creation,Роль по умолчанию при создании, @@ -3257,10 +3223,10 @@ Document type is required to create a dashboard chart,Тип документа Documentation Link,Документация Ссылка, Don't Import,Не импортировать, Don't Send Emails,Не отправлять электронные письма, -"Drag and drop files, ","Перетащите файлы,", +"Drag and drop files, ","Перетащите файлы, ", Drop,Бросить, Drop Here,Бросить тут, -Drop files here,Перетащите файлы сюда, +Drop files here,Поместите файлы сюда, Dynamic Template,Динамический шаблон, ERPNext Role,ERPNext роль, Email / Notifications,Уведомления по электронной почте, @@ -3407,7 +3373,7 @@ Last Update,Последнее обновление, Last refreshed,Последнее обновление, Link Document Type,Тип документа ссылки, Link Fieldname,Имя поля ссылки, -Loading import file...,Загрузка файла импорта..., +Loading import file...,Загрузка импортируемого файла..., Local Document Type,Локальный тип документа, Log Data,Данные журнала, Main Section (HTML),Основной раздел (HTML), @@ -3415,7 +3381,7 @@ Main Section (Markdown),Основной раздел (Markdown), "Maintains a Log of all inserts, updates and deletions on Event Producer site for documents that have consumers.","Ведение журнала всех вставок, обновлений и удалений на сайте Event Producer для документов, имеющих потребителей.", Maintains a log of every event consumed along with the status of the sync and a Resync button in case sync fails.,"Ведение журнала всех использованных событий, а также состояния синхронизации и кнопки Resync в случае сбоя синхронизации.", Make all attachments private,Сделайте все вложения приватными, -Mandatory Depends On,Обязательно зависит от, +Mandatory Depends On,Обязателен - зависит от, Map Columns,Столбцы карты, Map columns from {0} to fields in {1},Сопоставить столбцы из {0} с полями в {1}, Mapping column {0} to field {1},Отображение столбца {0} в поле {1}, @@ -3426,7 +3392,7 @@ Me,Мне, Mention,Упоминание, Modules,Модули, Monthly Long,Ежемесячно долго, -Naming Series,Идентификация по Имени, +Naming Series,Именование серии, Navigate Home,Навигация Домой, Navigate list down,Переместиться вниз по списку, Navigate list up,Навигация по списку вверх, @@ -3483,7 +3449,7 @@ Press Alt Key to trigger additional shortcuts in Menu and Sidebar,"Нажмит Print Settings...,Настройки печати..., Producer Document Name,Название документа производителя, Producer URL,URL производителя, -Property Depends On,Недвижимость зависит от, +Property Depends On,Свойства зависят от, Pull from Google Calendar,Загрузить из календаря Google, Pull from Google Contacts,Загрузить из контактов Google, Pulled from Google Calendar,Загружено из календаря Google, @@ -3493,7 +3459,7 @@ Push to Google Contacts,Нажмите на контакты Google, Queue / Worker,Очередь / Рабочий, RAW Information Log,Необработанный информационный журнал, Raw Printing Settings...,Настройки необработанной печати..., -Read Only Depends On,Только чтение зависит от, +Read Only Depends On,Только для чтения - зависит от, Recent Activity,Недавняя активность, Reference document has been cancelled,Справочный документ был отменен, Reload File,Перезагрузить файл, @@ -3526,6 +3492,7 @@ Select Date Range,Выберите диапазон дат, Select Field,Выберите поле, Select Field...,Выберите поле..., Select Filters,Выберите фильтры, +Edit Filters,Изменить фильтры, Select Google Calendar to which event should be synced.,"Выберите календарь Google, к которому нужно синхронизировать событие.", Select Google Contacts to which contact should be synced.,"Выберите Google Контакты, с которыми контакт должен быть синхронизирован.", Select Group By...,Выбрать группу по..., @@ -3646,7 +3613,7 @@ Workflow Status,Состояние рабочего процесса, You are not allowed to export {} doctype,Вы не можете экспортировать {} doctype, You can try changing the filters of your report.,Вы можете попробовать изменить фильтры вашего отчета., You do not have permissions to cancel all linked documents.,У вас нет прав для отмены всех связанных документов., -You need to create these first: ,Вам нужно сначала создать это: , +You need to create these first: ,Вам сначала нужно создать: , You need to enable JavaScript for your app to work.,Вам нужно включить JavaScript для вашего приложения для работы., You need to install pycups to use this feature!,"Вам нужно установить pycups, чтобы использовать эту функцию!", Your Target,Ваша цель, @@ -3708,7 +3675,7 @@ Currency,Валюта, Customize,Настроить, Daily,Ежедневно, Date,Дата, -Dear,Уважаемый (ая), +Dear,Уважаемый(ая), Default,По умолчанию, Delete,Удалить, Description,Описание, @@ -3727,7 +3694,7 @@ Entity Type,Тип объекта, Error,Ошибка, Expired,Истек срок действия, Export,Экспорт, -Export not allowed. You need {0} role to export.,Экспорт не допускается. Вам нужно {0} роль для экспорта., +Export not allowed. You need {0} role to export.,Экспорт не допускается. Вам нужна роль {0} для экспорта., Fetching...,Получение..., Field,Поле, File Manager,Файловый менеджер, @@ -3788,7 +3755,6 @@ Set,Задать, Setup,Настройки, Setup Wizard,Мастер установки, Size,Размер, -Sr,Sr, Start,Начать, Start Time,Стартовое время, Status,Статус, @@ -3798,7 +3764,7 @@ Template,Шаблон, Thursday,Четверг, Title,Заголовок, Total,Общая сумма, -Totals,Всего:, +Totals,Всего, Tuesday,Вторник, Type,Тип, Update,Обновить, @@ -3809,10 +3775,10 @@ Welcome to {0},Добро пожаловать в {0}, Year,Год, Yearly,Ежегодно, You,Вы, -You can also copy-paste this link in your browser,Ещё можно скопировать эту ссылку в браузер, +You can also copy-paste this link in your browser,Вы также можете скопировать и вставить эту ссылку в свой браузер, and,и, {0} Name,{0} Имя, -{0} is required,{0} требуется, +{0} is required,{0} является обязательным, ALL,ВСЕ, Attach File,Прикрепить файл, Barcode,Штрих-код, @@ -3887,7 +3853,6 @@ Hidden,Скрытый, Javascript,Javascript, Ldap settings,Настройки Ldap, Mobile number,Мобильный номер, -Mx,Mx, No,Нет, Not found,Не обнаружена, Notes:,Примечания:, @@ -3994,7 +3959,7 @@ Desk Page,Рабочий стол, Desk Shortcut,Сочетание клавиш, Developer Mode Only,Только режим разработчика, Disable User Customization,Отключить настройку пользователя, -For example: {} Open,Например: {} Open, +For example: {} Open,Например: {} Открыто, Link Cards,Карты ссылок, Link To,Ссылка к, Onboarding,Вводный, @@ -4026,6 +3991,7 @@ Select Language,Выбрать язык, Confirm Translations,Подтвердить перевод, Contributed Translations,Добавленные переводы, Show Tags,Показать теги, +Hide Tags,Скрыть теги, Do not have permission to access {0} bucket.,У вас нет разрешения на доступ к сегменту {0}., Allow document creation via Email,Разрешить создание документов по электронной почте, Sender Field,Поле отправителя, @@ -4218,12 +4184,12 @@ since last year,с прошлого года, Show,Показать, New Number Card,Карточка с новым номером, Your Shortcuts,Ваши ярлыки, -You haven't added any Dashboard Charts or Number Cards yet.,Вы еще не добавили диаграммы или карточки с цифрами., -Click On Customize to add your first widget,"Нажмите "Настроить", чтобы добавить свой первый виджет.", +You haven't added any Dashboard Charts or Number Cards yet.,Вы еще не добавили диаграммы или карточки с показателями., +Click On Customize to add your first widget,"Нажмите Настроить, чтобы добавить свой первый виджет.", Are you sure you want to reset all customizations?,"Вы уверены, что хотите сбросить все настройки?", "Couldn't save, please check the data you have entered","Не удалось сохранить, проверьте данные, которые вы ввели", Validation Error,Ошибка проверки, -"You can only upload JPG, PNG, PDF, or Microsoft documents.","Вы можете загружать только документы в форматах JPG, PNG, PDF или Microsoft.", +"You can only upload JPG, PNG, PDF, or Microsoft documents.","Вы можете загружать только документы в форматах JPG, PNG, PDF или документы Microsoft.", Reverting length to {0} for '{1}' in '{2}'. Setting the length as {3} will cause truncation of data.,Возврат длины к {0} для '{1}' в '{2}'. Установка длины как {3} вызовет усечение данных., '{0}' not allowed for type {1} in row {2},'{0}' не разрешено для типа {1} в строке {2}, Option {0} for field {1} is not a child table,Вариант {0} для поля {1} не является дочерней таблицей, @@ -4437,7 +4403,7 @@ CTA,CTA, CTA Label,Метка CTA, CTA URL,CTA URL, Default Portal Home,Главная страница портала по умолчанию, -"Example: ""/desk""",Пример: "/ стол", +"Example: ""/desk""","Пример: ""/desk""", Social Link Settings,Настройки социальных ссылок, Social Link Type,Тип социальной ссылки, facebook,facebook, @@ -4543,11 +4509,11 @@ Too Many Requests,Слишком много запросов, {} is not a valid date string.,{} не является допустимой строкой даты., Invalid Date,Недействительная дата, Please select a valid date filter,"Пожалуйста, выберите действующий фильтр даты", -Value {0} must be in the valid duration format: d h m s,Значение {0} должно иметь допустимый формат продолжительности: dhms., +Value {0} must be in the valid duration format: d h m s,Значение {0} должно иметь допустимый формат продолжительности: д ч м с, Google Sheets URL is invalid or not publicly accessible.,URL-адрес Google Таблиц недействителен или не является общедоступным., "Google Sheets URL must end with ""gid={number}"". Copy and paste the URL from the browser address bar and try again.",URL-адрес Google Таблиц должен заканчиваться на "gid = {number}". Скопируйте и вставьте URL-адрес из адресной строки браузера и повторите попытку., Incorrect URL,Неверный URL, -"""{0}"" is not a valid Google Sheets URL","{0}" не является действительным URL-адресом Google Таблиц, +"""{0}"" is not a valid Google Sheets URL","""{0}"" не является действительным URL-адресом Google Таблиц", Duplicate Name,Повторяющееся имя, "Please check the value of ""Fetch From"" set for field {0}","Проверьте значение параметра "Получить из", установленное для поля {0}.", Wrong Fetch From value,Неверное значение Fetch From, @@ -4567,7 +4533,7 @@ Hourly comment limit reached for: {0},Достигнут лимит почасо Please add a valid comment.,"Пожалуйста, добавьте действительный комментарий.", Document {0} Already Restored,Документ {0} уже восстановлен, Restoring Deleted Document,Восстановление удаленного документа, -{function} of {fieldlabel},{функция} из {fieldlabel}, +{function} of {fieldlabel},{function} из {fieldlabel}, Invalid template file for import,Неверный файл шаблона для импорта, Invalid or corrupted content for import,Недействительный или поврежденный контент для импорта, Value {0} must in {1} format,Значение {0} должно быть в формате {1}, @@ -4575,7 +4541,7 @@ Value {0} must in {1} format,Значение {0} должно быть в фо Could not map column {0} to field {1},Не удалось сопоставить столбец {0} с полем {1}, Skipping Duplicate Column {0},Пропуск повторяющегося столбца {0}, The column {0} has {1} different date formats. Automatically setting {2} as the default format as it is the most common. Please change other values in this column to this format.,"Столбец {0} имеет {1} разные форматы даты. Автоматическая установка {2} в качестве формата по умолчанию, поскольку он является наиболее распространенным. Измените другие значения в этом столбце на этот формат.", -You have reached the hourly limit for generating password reset links. Please try again later.,"Вы достигли почасового лимита для создания ссылок для сброса пароля. Пожалуйста, попробуйте позже.", +You have reached the hourly limit for generating password reset links. Please try again later.,"Вы достигли лимита на создание ссылок для сброса пароля. Пожалуйста, попробуйте позже.", Please hide the standard navbar items instead of deleting them,Скройте стандартные элементы навигационной панели вместо их удаления, DocType's name should not start or end with whitespace,Имя DocType не должно начинаться или заканчиваться пробелом, File name cannot have {0},Имя файла не может содержать {0}, @@ -4600,14 +4566,14 @@ Delivery Failed,Доставка не удалась, Twilio WhatsApp Message Error,Ошибка сообщения Twilio WhatsApp, A featured post must have a cover image,В избранном посте должна быть обложка., Load More,Показать больше, -Published on,Опубликован в, +Published on,Опубликован, Enable developer mode to create a standard Web Template,"Включите режим разработчика, чтобы создать стандартный веб-шаблон", Was this article helpful?,Эта статья была полезной?, Thank you for your feedback!,Спасибо за ваш отзыв!, New Mention on {0},Новое упоминание о {0}, Assignment Update on {0},Обновление задания на {0}, New Document Shared {0},Новый документ опубликован {0}, -Energy Point Update on {0},Обновление Energy Point от {0}, +Energy Point Update on {0},Обновление баллов активности от {0}, You cannot create a dashboard chart from single DocTypes,Вы не можете создать диаграмму панели мониторинга из одного типа документов, Invalid json added in the custom options: {0},В настраиваемые параметры добавлен недопустимый json: {0}, Invalid JSON in card links for {0},Недействительный JSON в ссылках на карточки для {0}, @@ -4629,7 +4595,7 @@ Worflow States Don't Exist,Состояния Worflow не существуют, Save Anyway,Все равно сохранить, Energy Points:,Баллы активности:, Review Points:,Баллы обзора:, -Rank:,Ранг:, +Rank:,Рейтинг:, Monthly Rank:,Месячный рейтинг:, Invalid expression set in filter {0} ({1}),Недопустимое выражение в фильтре {0} ({1}), Invalid expression set in filter {0},В фильтре {0} задано недопустимое выражение, @@ -4688,12 +4654,12 @@ Open URL in a New Tab,Открыть URL в новой вкладке, Align Right,Выровнять по правому краю, Loading Filters...,Загрузка фильтров..., Count Customizations,Подсчет настроек, -For Example: {} Open,Например: {} Открыть, +For Example: {} Open,Например: {} Открыто, Choose Existing Card or create New Card,Выберите существующую карту или создайте новую карту, Number Cards,Числовые карты, Function Based On,Функция на основе, Add Filters,Добавить фильтры, -Skip,Пропускать, +Skip,Пропустить, Dismiss,Отклонить, Value cannot be negative for,Значение не может быть отрицательным для, Value cannot be negative for {0}: {1},Значение не может быть отрицательным для {0}: {1}, @@ -4702,9 +4668,28 @@ Authentication failed while receiving emails from Email Account: {0}.,Ошибк Message from server: {0},Сообщение с сервера: {0}, Documentation,Документация, User Forum,Форум пользователей, -Report an issue,Сообщить об ошибке, +Report an Issue,Сообщить об ошибке, +About,О системе, My Profile,Мой профиль, My Settings,Мои настройки, Toggle Full Width,Переключить ширину, Toggle Theme,Переключить тему, Modules,Модули, +You created this {0},Вы создали это {0}, +{0} created this {1},{0} создал(а) это {1}, +You edited this {0},Вы отредактировали это {0}, +{0} edited this {1},{0} отредактировал(а) это {1}, +You viewed this {0},Вы просмотрели это {0}, +{0} viewed this {1},{0} просмотрел(а) это {1}, +Apply Filters,Применить фильтры, ++ Add a Filter,+ Добавить фильтр, +Is Template,Является шаблоном, +Show Saved,Показать сохраненные, +Hide Saved,Скрыть сохраненные, +Add Tags,Добавить теги, +Page Size,Формат страницы, +Set all public,Сделать публичными, +Set all private,Сделать приватными, +Drag and drop files here or upload from,Перетащите файлы сюда или загрузите из, +My Device,Моё устройство, +Library,Библиотека, From 04f4fd8cfc4dc9cf9b4dd4696e23ea2ab0d0b5c3 Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:00:54 +0530 Subject: [PATCH 23/23] fix: Redirect to comment in the doc comment section (#17538) --- frappe/templates/includes/comments/comments.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/frappe/templates/includes/comments/comments.py b/frappe/templates/includes/comments/comments.py index c316db37fd..44963051ca 100644 --- a/frappe/templates/includes/comments/comments.py +++ b/frappe/templates/includes/comments/comments.py @@ -3,7 +3,7 @@ import re import frappe -from frappe import _ +from frappe import _, scrub from frappe.rate_limiter import rate_limit from frappe.utils.html_utils import clean_html from frappe.website.doctype.blog_settings.blog_settings import get_comment_limit @@ -41,8 +41,13 @@ def add_comment(comment, comment_email, comment_by, reference_doctype, reference if route: clear_cache(route) - content = comment.content + "

{}

".format( - frappe.utils.get_request_site_address(), doc.route, comment.name, _("View Comment") + if doc.get("route"): + url = f"{frappe.utils.get_request_site_address()}/{doc.route}#{comment.name}" + else: + url = f"{frappe.utils.get_request_site_address()}/app/{scrub(doc.doctype)}/{doc.name}#comment-{comment.name}" + + content = comment.content + "

{}

".format( + url, _("View Comment") ) if doc.doctype == "Blog Post" and not doc.enable_email_notification:
{{ frappe.meta.get_label(doc.ref_doctype, table_info[0]) }} {{ table_info[1] }} {{ item[0] }}{{ item[1] }}{{ item[2] }}{{ item[1] }}{{ item[2] }}