Merge branch 'develop' into capture-client-events

This commit is contained in:
mergify[bot] 2026-01-05 07:22:11 +00:00 committed by GitHub
commit efc236ef37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 109 additions and 46 deletions

View file

@ -6,18 +6,32 @@ def execute():
batch_size = 10_000
while True:
frappe.db.sql(
"""
update `tabCommunication Link` cl
inner join `tabCommunication` c on cl.parent = c.name
set cl.communication_date = c.communication_date
where cl.communication_date is null
and c.communication_date is not null
limit %s
""",
frappe.db.multisql(
{
"mariadb": """
update `tabCommunication Link` cl
inner join `tabCommunication` c on cl.parent = c.name
set cl.communication_date = c.communication_date
where cl.communication_date is null
and c.communication_date is not null
limit %s
""",
"postgres": """
UPDATE "tabCommunication Link"
SET communication_date = sub.communication_date
FROM (
SELECT cl.name, c.communication_date
FROM "tabCommunication Link" cl
JOIN "tabCommunication" c ON cl.parent = c.name
WHERE cl.communication_date IS NULL
AND c.communication_date IS NOT NULL
LIMIT %s
) AS sub
WHERE "tabCommunication Link".name = sub.name
""",
},
(batch_size,),
)
frappe.db.commit()
if not frappe.db.sql(

View file

@ -59,6 +59,7 @@
"view_switcher",
"form_settings_section",
"form_sidebar",
"form_navigation_buttons",
"timeline",
"dashboard",
"show_absolute_datetime_in_timeline",
@ -850,6 +851,12 @@
"is_virtual": 1,
"label": "Active Sessions",
"options": "User Session Display"
},
{
"default": "1",
"fieldname": "form_navigation_buttons",
"fieldtype": "Check",
"label": "Navigation Buttons"
}
],
"icon": "fa fa-user",
@ -903,7 +910,7 @@
}
],
"make_attachments_public": 1,
"modified": "2025-12-13 12:53:46.486021",
"modified": "2026-01-02 16:00:51.406511",
"modified_by": "Administrator",
"module": "Core",
"name": "User",

View file

@ -48,6 +48,7 @@ desk_properties = (
"bulk_actions",
"view_switcher",
"form_sidebar",
"form_navigation_buttons",
"timeline",
"dashboard",
)
@ -96,6 +97,7 @@ class User(Document):
follow_created_documents: DF.Check
follow_liked_documents: DF.Check
follow_shared_documents: DF.Check
form_navigation_buttons: DF.Check
form_sidebar: DF.Check
full_name: DF.Data | None
gender: DF.Link | None

View file

@ -446,9 +446,20 @@
bottom: 4%;
right: 4%;
z-index: 100;
opacity: 0.1;
opacity: 0.5;
}
.desktop-edit:hover{
opacity: 1;
transition: opacity 0.3s;
}
[data-theme="dark"] .desktop-edit{
background-color: var(--surface-gray-3);
opacity: 1;
}
[data-theme="dark"] .desktop-edit:hover{
opacity: 0.8;
transition: opacity 0.3s;
}

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-12-21 09:35+0000\n"
"PO-Revision-Date: 2025-12-24 20:23\n"
"PO-Revision-Date: 2026-01-03 23:05\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
@ -133,7 +133,15 @@ msgid "0 - too guessable: risky password.\n"
"3 - safely unguessable: moderate protection from offline slow-hash scenario.\n"
"<br>\n"
"4 - very unguessable: strong protection from offline slow-hash scenario."
msgstr ""
msgstr "0 - слишком легко угадывается: рискованный пароль.\n"
"<br>\n"
"1 - очень легко угадывается: защита от атак с ограничением скорости. \n"
"<br>\n"
"2 - относительно легко угадывается: защита от атак без ограничения скорости.\n"
"<br>\n"
"3 - практически невозможно угадать: умеренная защита от сценариев с медленным хешированием в офлайн-режиме.\n"
"<br>\n"
"4 - очень трудно угадать: надежная защита от сценариев с медленным хешированием в офлайн-режиме."
#. Description of the 'Priority' (Int) field in DocType 'Web Page'
#: frappe/website/doctype/web_page/web_page.json
@ -1466,7 +1474,7 @@ msgstr "Добавить новую вкладку"
#: frappe/utils/password_strength.py:191
msgid "Add numbers or special characters."
msgstr ""
msgstr "Добавьте цифры или специальные символы."
#: frappe/public/js/print_format_builder/PrintFormatSection.vue:125
msgid "Add page break"
@ -5217,7 +5225,7 @@ msgstr "Распространенные имена и фамилии легко
#: frappe/utils/password_strength.py:190
msgid "Common words are easy to guess."
msgstr ""
msgstr "Общие слова легко угадать."
#. Name of a DocType
#. Option for the 'Communication Type' (Select) field in DocType
@ -5912,7 +5920,7 @@ msgstr "Создать новую Канбан доску"
#: frappe/public/js/frappe/list/list_filter.js:101
msgid "Create Saved Filter"
msgstr ""
msgstr "Создать сохраненный фильтр"
#: frappe/core/doctype/user/user.js:271
msgid "Create User Email"
@ -12025,7 +12033,7 @@ msgstr "Помощь HTML"
#. Description of the 'Content' (Text Editor) field in DocType 'Note'
#: frappe/desk/doctype/note/note.json
msgid "Help: To link to another record in the system, use \"/desk/note/[Note Name]\" as the Link URL. (don't use \"http://\")"
msgstr ""
msgstr "Помощь: Для ссылки на другую запись в системе используйте \"/desk/note/[Имя заметки]\" в качестве ссылки (не используйте \"http://\")"
#. Label of the helpful (Int) field in DocType 'Help Article'
#: frappe/website/doctype/help_article/help_article.json
@ -17498,7 +17506,7 @@ msgstr "Не найден шаблон по пути: {0}"
#: frappe/core/page/permission_manager/permission_manager.js:362
msgid "No user has the role <strong>{0}</strong>"
msgstr ""
msgstr "Нет пользователя с ролью <strong>{0}</strong>"
#: frappe/public/js/frappe/form/controls/multiselect_list.js:276
msgid "No values to show"
@ -19124,7 +19132,7 @@ msgstr "Пароль не найден для {0} {1} {2}"
#: frappe/core/doctype/user/user.py:1307
msgid "Password requirements not met"
msgstr ""
msgstr "Пароль не соответствует требованиям"
#: frappe/core/doctype/user/user.py:1140
msgid "Password reset instructions have been sent to {}'s email"
@ -28580,7 +28588,7 @@ msgstr "Используйте TLS"
#: frappe/utils/password_strength.py:191
msgid "Use a few uncommon words together."
msgstr ""
msgstr "Используйте несколько редких слов вместе."
#: frappe/utils/password_strength.py:44
msgid "Use a few words, avoid common phrases."
@ -29334,7 +29342,7 @@ msgstr "Посмотреть веб-сайт"
#: frappe/core/page/permission_manager/permission_manager.js:395
msgid "View all {0} users"
msgstr ""
msgstr "Просмотреть всех {0} пользователей"
#: frappe/www/confirm_workflow_action.html:12
msgid "View document"
@ -29456,7 +29464,7 @@ msgstr "Предупреждение: Обновление счетчика мо
#: frappe/core/doctype/doctype/doctype.py:458
msgid "Warning: Usage of 'format:' is discouraged."
msgstr ""
msgstr "Внимание: использование конструкции 'format:' не рекомендуется."
#: frappe/website/doctype/help_article/templates/help_article.html:24
msgid "Was this article helpful?"
@ -30472,7 +30480,7 @@ msgstr "Вы можете задать только 3 пользовательс
#: frappe/handler.py:184
msgid "You can only upload JPG, PNG, GIF, PDF, TXT, CSV or Microsoft documents."
msgstr ""
msgstr "Вы можете загружать только документы в форматах JPG, PNG, GIF, PDF, TXT, CSV или Microsoft."
#: frappe/core/doctype/data_export/exporter.py:199
msgid "You can only upload upto 5000 records in one go. (may be less in some cases)"
@ -32285,7 +32293,7 @@ msgstr "{0} недель назад"
#: frappe/core/page/permission_manager/permission_manager.js:378
msgid "{0} with the role <strong>{1}</strong>"
msgstr ""
msgstr "{0} с ролью <strong>{1}</strong>"
#: frappe/public/js/frappe/utils/pretty_date.js:39
msgid "{0} y"

View file

@ -88,14 +88,16 @@ frappe.ui.form.PrintView = class {
icon: "refresh",
});
this.page.add_action_icon(
"es-line-filetype",
() => {
this.go_to_form_view();
},
"",
__("Form")
);
if (frappe.is_mobile()) {
this.page.add_button(__("Form"), () => this.go_to_form_view(), { icon: "small-file" });
} else {
this.page.add_action_icon(
"es-line-filetype",
() => this.go_to_form_view(),
"",
__("Form")
);
}
}
setup_sidebar() {

View file

@ -11,7 +11,8 @@ frappe.ui.form.Share = class Share {
}
render_sidebar() {
const shared = this.shared || this.frm.get_docinfo().shared;
const shared_users = shared.filter(Boolean).map((s) => s.user);
const has_everyone = shared.some((s) => s && s.everyone);
const shared_users = shared.filter((s) => s && s.user && !s.everyone).map((s) => s.user);
if (this.frm.is_new()) {
this.parent.find(".share-doc-btn").hide();
@ -26,7 +27,7 @@ frappe.ui.form.Share = class Share {
this.shares.empty();
if (!shared_users.length) {
if (!shared_users.length && !has_everyone) {
this.shares.hide();
return;
}
@ -36,7 +37,12 @@ frappe.ui.form.Share = class Share {
avatar_group.on("click", () => {
this.frm.share_doc();
});
// REDESIGN-TODO: handle "shared with everyone"
if (has_everyone) {
avatar_group.prepend(
frappe.avatar_group(["Everyone"], 1, { align: "left", overlap: true })
);
}
this.shares.append(avatar_group);
}
show() {

View file

@ -318,9 +318,12 @@ frappe.ui.form.Toolbar = class Toolbar {
this.page.clear_menu();
if (frappe.boot.desk_settings.form_sidebar) {
// this.make_navigation();
this.make_menu_items();
}
if (frappe.boot.desk_settings.form_navigation_buttons) {
this.make_navigation();
}
}
make_navigation() {

View file

@ -770,6 +770,7 @@ frappe.ui.Page = class Page {
if (icon) {
title = `${frappe.utils.icon(icon)} ${title}`;
}
let title_wrapper = this.$title_area.find(".title-text");
title_wrapper.html(title);
title_wrapper.attr("title", __(tooltip_label) || this.title);

View file

@ -224,7 +224,8 @@ frappe.breadcrumbs = {
if (docname.startsWith("new-" + doctype.toLowerCase().replace(/ /g, "-"))) {
docname_title = __("New {0}", [__(doctype)]);
} else {
docname_title = doc.name;
let title = frappe.model.get_doc_title(doc);
docname_title = title || doc.name;
}
this.append_breadcrumb_element(form_route, docname_title, "title-text-form");
@ -238,7 +239,12 @@ frappe.breadcrumbs = {
last_crumb.css("cursor", "copy");
last_crumb.click((event) => {
event.stopImmediatePropagation();
frappe.utils.copy_to_clipboard(last_crumb.text());
frappe.utils.copy_to_clipboard(doc.name);
});
last_crumb.attr("title", __("Click to copy name"));
last_crumb.tooltip({
delay: { show: 100, hide: 100 },
trigger: "hover",
});
}
},

View file

@ -166,7 +166,7 @@
}
.nav-item {
margin-left: 0px;
margin-left: -5px;
}
}

View file

@ -47,6 +47,8 @@ class TestSQLiteSearchAPI(IntegrationTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
frappe.db.delete("Note")
frappe.db.delete("ToDo")
cls.search = TestSQLiteSearch()
# Clean up any existing test database
cls.search.drop_index()

View file

@ -109,9 +109,10 @@ def get_error_metadata() -> str:
metadata["form_dict"] = sanitized_dict(frappe.form_dict)
metadata["user"] = getattr(frappe.session, "user", "Unidentified")
finally:
except Exception:
# We don't want to bother with exception handling *while* gathering some error's metadata
return frappe.as_json(metadata) # noqa: B012
pass
return frappe.as_json(metadata)
def log_error_snapshot(exception: Exception):

View file

@ -113,7 +113,7 @@
"type": "Link"
},
{
"child": 0,
"child": 1,
"collapsible": 1,
"icon": "settings",
"indent": 0,
@ -125,7 +125,7 @@
"type": "Link"
},
{
"child": 0,
"child": 1,
"collapsible": 1,
"icon": "list",
"indent": 0,
@ -137,7 +137,7 @@
"type": "Link"
},
{
"child": 0,
"child": 1,
"collapsible": 1,
"icon": "list",
"indent": 0,
@ -149,7 +149,7 @@
"type": "Link"
}
],
"modified": "2025-12-18 17:22:26.558605",
"modified": "2025-12-29 23:46:47.024937",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Integrations",