Merge branch 'frappe:develop' into tabs_on_grid_row_form

This commit is contained in:
avc 2025-12-09 21:04:39 +01:00 committed by GitHub
commit 9c06b6e089
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 908 additions and 678 deletions

View file

@ -3,7 +3,7 @@ const jump_to_field = (field_label) => {
.type("{esc}") // lose focus if any
.type("{ctrl+j}") // jump to field
.type(field_label)
.wait(500)
.wait(1000)
.type("{enter}")
.wait(200)
.findByRole("button", { name: "Go" })

View file

@ -528,18 +528,27 @@ def get_sentry_dsn():
def get_sidebar_items():
from frappe.desk.doctype.workspace_sidebar.workspace_sidebar import auto_generate_sidebar_from_module
sidebars = frappe.get_all(
"Workspace Sidebar", fields=["name", "header_icon"], filters={"name": ["not like", "%My Workspaces%"]}
)
module_sidebars = auto_generate_sidebar_from_module()
sidebars.extend(module_sidebars)
add_user_specific_sidebar(sidebars)
sidebar_items = {}
for s in sidebars:
w = frappe.get_doc("Workspace Sidebar", s["name"])
sidebar_items[s["name"].lower()] = {
"label": s["name"],
sidebar_title = s.get("name")
if sidebar_title:
w = frappe.get_doc("Workspace Sidebar", sidebar_title)
else:
sidebar_title = s.title
w = s
sidebar_items[sidebar_title.lower()] = {
"label": sidebar_title,
"items": [],
"header_icon": s["header_icon"],
"header_icon": s.get("header_icon"),
"module": w.module,
"app": w.app,
}
@ -568,13 +577,12 @@ def get_sidebar_items():
"report_type": report_type,
"ref_doctype": ref_doctype,
}
if (
"My Workspaces" in s["name"]
"My Workspaces" in sidebar_title
or si.type == "Section Break"
or w.is_item_allowed(si.link_to, si.link_type)
):
sidebar_items[s["name"].lower()]["items"].append(workspace_sidebar)
sidebar_items[sidebar_title.lower()]["items"].append(workspace_sidebar)
old_name = f"my workspaces-{frappe.session.user.lower()}"
if old_name in sidebar_items.keys():

View file

@ -157,7 +157,7 @@ class TestServerScript(IntegrationTestCase):
self.assertEqual(frappe.get_doc("Server Script", "test_return_value").execute_method(), "hello")
def test_permission_query(self):
sql = frappe.db.get_list("ToDo", run=False)
sql = frappe.db.get_list("ToDo", run=False).get_sql()
self.assertTrue("where (1 = 1)" in sql.lower())
self.assertTrue(isinstance(frappe.db.get_list("ToDo"), list))

View file

@ -20,7 +20,7 @@ frappe.pages["dashboard-view"].on_page_load = function (wrapper) {
class Dashboard {
constructor(wrapper) {
this.wrapper = $(wrapper);
$(`<div class="dashboard" style="overflow: visible; margin: var(--margin-sm);">
$(`<div class="dashboard" style="overflow: visible; margin: var(--margin-md);">
<div class="dashboard-graph"></div>
</div>`).appendTo(this.wrapper.find(".page-content").empty());
this.container = this.wrapper.find(".dashboard-graph");

View file

@ -1089,22 +1089,22 @@ class Database:
Query will be built as:
```sql
UPDATE `tabItem`
UPDATE `tabTask`
SET `status` = CASE
WHEN `name` = 'Item-1' THEN 'Close'
WHEN `name` = 'Item-2' THEN 'Open'
WHEN `name` = 'Item-3' THEN 'Close'
WHEN `name` = 'Item-4' THEN 'Cancelled'
WHEN `name` = 'TASK-0001' THEN 'Closed'
WHEN `name` = 'TASK-0002' THEN 'Open'
WHEN `name` = 'TASK-0003' THEN 'Closed'
WHEN `name` = 'TASK-0004' THEN 'Cancelled'
ELSE `status`
end,
END,
`description` = CASE
WHEN `name` = 'Item-1' THEN 'This is the first task'
WHEN `name` = 'Item-2' THEN 'This is the second task'
WHEN `name` = 'Item-3' THEN 'This is the third task'
WHEN `name` = 'Item-4' THEN 'This is the fourth task'
WHEN `name` = 'TASK-0001' THEN 'This is the first task'
WHEN `name` = 'TASK-0002' THEN 'This is the second task'
WHEN `name` = 'TASK-0003' THEN 'This is the third task'
WHEN `name` = 'TASK-0004' THEN 'This is the fourth task'
ELSE `description`
end
WHERE `name` IN ( 'Item-1', 'Item-2', 'Item-3', 'Item-4' )
END
WHERE `name` IN ('TASK-0001', 'TASK-0002', 'TASK-0003', 'TASK-0004');
```
"""
if not doc_updates:

View file

@ -79,6 +79,44 @@ def _apply_date_field_filter_conversion(value, operator: str, doctype: str, fiel
return value
def _apply_datetime_field_filter_conversion(between_values: tuple | list, doctype: str, field) -> tuple:
"""Apply date to datetime conversion for Datetime fields with 'between' operator.
Args:
between_values: Tuple/list of two values [from, to] for between filter
doctype: DocType name
field: Field name or pypika Field object
Returns:
Tuple with dates expanded to datetime ranges for Datetime fields
"""
from frappe.model.db_query import _convert_type_for_between_filters
# Extract field name
field_name = field
if "." in str(field):
field_name = field.split(".")[-1]
# Skip querying meta for core doctypes to avoid recursion
if doctype in CORE_DOCTYPES:
df = None
else:
meta = frappe.get_meta(doctype)
df = meta.get_field(field_name) if meta else None
# Standard datetime fields or Datetime fieldtype
if not (field_name in ("creation", "modified") or (df and df.fieldtype == "Datetime")):
return between_values
from_val, to_val = between_values
# Convert to datetime using db_query helper (handles strings, dates, datetimes)
from_val = _convert_type_for_between_filters(from_val, set_time=datetime.time())
to_val = _convert_type_for_between_filters(to_val, set_time=datetime.time(23, 59, 59, 999999))
return (from_val, to_val)
if TYPE_CHECKING:
from frappe.query_builder import DocType
@ -487,12 +525,22 @@ class Engine:
frappe.throw(_("Document cannot be used as a filter value"))
_operator = operator
if _operator.lower() in ("timespan", "previous", "next"):
from frappe.model.db_query import get_date_range
_value = get_date_range(_operator.lower(), _value)
_operator = "between"
# For Date fields with datetime values, convert to date to match db_query behavior
if isinstance(_value, datetime.datetime) or (
isinstance(_value, list | tuple) and any(isinstance(v, datetime.datetime) for v in _value)
):
_value = _apply_date_field_filter_conversion(_value, _operator, doctype or self.doctype, field)
# For Datetime fields with date values and 'between' operator, convert to datetime range to match db_query
if _operator.lower() == "between" and isinstance(_value, list | tuple) and len(_value) == 2:
_value = _apply_datetime_field_filter_conversion(_value, doctype or self.doctype, field)
if not _value and isinstance(_value, list | tuple | set):
_value = ("",)

View file

@ -12,6 +12,7 @@ from frappe.boot import get_allowed_pages, get_allowed_reports
from frappe.model.document import Document
from frappe.modules.export_file import strip_default_fields
from frappe.modules.utils import create_directory_on_app_path
from frappe.utils.caching import site_cache
class WorkspaceSidebar(Document):
@ -240,3 +241,134 @@ def add_to_my_workspace(workspace):
except Exception as e:
frappe.log_error(title="Error in Adding Private Workspaces", message=e)
@site_cache()
def auto_generate_sidebar_from_module():
"""Auto generate sidebar from module"""
sidebars = []
for module in frappe.get_all("Module Def", pluck="name"):
if not (
frappe.db.exists("Workspace Sidebar", {"module": module})
or frappe.db.exists("Workspace Sidebar", {"name": module})
):
module_info = get_module_info(module)
sidebar_items = create_sidebar_items(module_info)
sidebar = frappe.new_doc("Workspace Sidebar")
sidebar.title = module
sidebar.items = sidebar_items
sidebar.module = module
sidebar.header_icon = "hammer"
sidebar.app = frappe.local.module_app.get(frappe.scrub(module), None)
sidebars.append(sidebar)
return sidebars
def get_module_info(module_name):
entities = ["Workspace", "Dashboard", "DocType", "Report", "Page"]
module_info = {}
for entity in entities:
module_info[entity] = {}
filters = [{"module": module_name}]
pluck = "name"
fieldnames = ["name"]
if entity.lower() == "doctype":
filters.append({"istable": 0})
if entity.lower() == "page":
fieldnames.append("title")
pluck = None
module_info[entity] = frappe.get_all(
entity, filters=filters, fields=fieldnames, pluck=pluck, order_by="creation asc"
)
# if module info has no workspaces, then move doctypes to the front
if not module_info.get("Workspace"):
module_info = {
"DocType": module_info.get("DocType"),
"Workspace": module_info.get("Workspace"),
"Report": module_info.get("Report"),
"Dashboard": module_info.get("Dashboard"),
"Page": module_info.get("Page"),
}
top_doctypes = choose_top_doctypes(module_info.get("DocType"))
if top_doctypes:
module_info["DocType"] = choose_top_doctypes(module_info.get("DocType"))
return module_info
def choose_top_doctypes(doctype_names):
doctype_limit = 3
if len(doctype_names) > doctype_limit:
try:
doctype_count_map = {}
for doctype in doctype_names:
doctype_count_map[doctype] = frappe.db.count(doctype)
top_doctypes = [
name
for name, count in sorted(doctype_count_map.items(), key=lambda x: x[1], reverse=True)[
:doctype_limit
]
]
return top_doctypes
except frappe.db.ProgrammingError:
# catches table not found errors
return None
def create_sidebar_items(module_info):
sidebar_items = []
idx = 1
section_entities = {"report": "Reports", "dashboard": "Dashboards", "page": "Pages"}
for entity, items in module_info.items():
section_break_added = False
entity_lower = entity.lower()
if entity_lower in section_entities:
if entity_lower == "report":
section_break = add_section_breaks("Reports", idx)
elif entity_lower in ("dashboard", "page") and len(items) > 1:
section_break = add_section_breaks(section_entities[entity_lower], idx)
section_break_added = True
sidebar_items.append(section_break)
idx += 1
for item in items:
item_info = {"label": item, "type": "Link", "link_type": entity, "link_to": item, "idx": idx}
if entity_lower == "report":
item_info["child"] = 1
item_info["icon"] = "table"
if entity_lower == "page":
item_info["label"] = item.get("title")
item_info["link_to"] = item.get("name")
if entity_lower == "workspace":
item_info["icon"] = "home"
item_info["icon"] = "wallpaper"
if entity_lower == "page":
item_info["icon"] = "panel-top"
if entity_lower == "doctype" and "settings" in item.lower():
item_info["icon"] = "settings"
if section_break_added:
item_info["child"] = 1
sidebar_item = frappe.new_doc("Workspace Sidebar Item")
sidebar_item.update(item_info)
sidebar_items.append(sidebar_item)
idx += 1
return sidebar_items
def add_section_breaks(label, idx):
section_break = frappe.new_doc("Workspace Sidebar Item")
section_break.update({"label": label, "type": "Section Break", "idx": idx})
return section_break

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-11-30 09:34+0000\n"
"PO-Revision-Date: 2025-12-02 15:00\n"
"PO-Revision-Date: 2025-12-06 16:40\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Persian\n"
"MIME-Version: 1.0\n"
@ -1660,7 +1660,7 @@ msgstr "به API Indexing Access اجازه دهید"
#: frappe/core/doctype/doctype/doctype.json
#: frappe/custom/doctype/customize_form/customize_form.json
msgid "Allow Auto Repeat"
msgstr "تکرار خودکار مجاز است"
msgstr "اجازه تکرار خودکار"
#. Label of the allow_bulk_edit (Check) field in DocType 'DocField'
#. Label of the allow_bulk_edit (Check) field in DocType 'Customize Form Field'
@ -1743,7 +1743,7 @@ msgstr "اجازه دادن به پیوندهای نمای وب قدیمی (نا
#. Settings'
#: frappe/printing/doctype/print_settings/print_settings.json
msgid "Allow Print for Cancelled"
msgstr "چاپ برای لغو مجاز است"
msgstr "اجازه چاپ برای لغو شده"
#. Label of the allow_print_for_draft (Check) field in DocType 'Print Settings'
#: frappe/automation/doctype/auto_repeat/auto_repeat.py:438
@ -6756,7 +6756,7 @@ msgstr "وضعیت ها و قوانین گردش کار را برای یک سن
#. Option for the 'Delivery Status' (Select) field in DocType 'Communication'
#: frappe/core/doctype/communication/communication.json
msgid "Delayed"
msgstr ""
msgstr "با تاخیر"
#. Label of the delete (Check) field in DocType 'Custom DocPerm'
#. Label of the delete (Check) field in DocType 'DocPerm'
@ -6949,7 +6949,7 @@ msgstr "جداکننده باید یک کاراکتر واحد باشد"
#. Label of the delivery_status (Select) field in DocType 'Communication'
#: frappe/core/doctype/communication/communication.json
msgid "Delivery Status"
msgstr ""
msgstr "وضعیت تحویل"
#. Option for the 'Sign ups' (Select) field in DocType 'Social Login Key'
#: frappe/integrations/doctype/social_login_key/social_login_key.json
@ -6960,7 +6960,7 @@ msgstr "انکار"
#. Label of the department (Data) field in DocType 'Contact'
#: frappe/contacts/doctype/contact/contact.json
msgid "Department"
msgstr ""
msgstr "دپارتمان"
#. Label of the dependencies (Data) field in DocType 'Workspace Link'
#: frappe/desk/doctype/workspace_link/workspace_link.json
@ -15693,7 +15693,7 @@ msgstr "استفاده از حافظه"
#: frappe/core/report/prepared_report_analytics/prepared_report_analytics.py:63
msgid "Memory Usage in MB"
msgstr ""
msgstr "میزان استفاده از حافظه برحسب مگابایت"
#. Option for the 'Type' (Select) field in DocType 'Notification Log'
#: frappe/desk/doctype/notification_log/notification_log.json
@ -18464,7 +18464,7 @@ msgstr "تولید PDF در حال انجام است"
#. Label of the pdf_generator (Select) field in DocType 'Print Format'
#: frappe/printing/doctype/print_format/print_format.json
msgid "PDF Generator"
msgstr ""
msgstr "سازنده PDF"
#. Label of the pdf_page_height (Float) field in DocType 'Print Settings'
#: frappe/printing/doctype/print_settings/print_settings.json
@ -19087,7 +19087,7 @@ msgstr "نوع مجوز"
#: frappe/core/doctype/permission_type/permission_type.py:40
msgid "Permission Type '{0}' is reserved. Please choose another name."
msgstr ""
msgstr "نوع مجوز '{0}' رزرو شده است. لطفاً نام دیگری انتخاب کنید."
#. Label of the section_break_4 (Section Break) field in DocType 'Custom
#. DocPerm'
@ -19325,7 +19325,7 @@ msgstr ""
#: frappe/core/doctype/data_import/data_import.js:164
msgid "Please click on 'Export Errored Rows', fix the errors and import again."
msgstr ""
msgstr "لطفاً روی «برون‌بُرد ردیف‌های دارای خطا» کلیک کنید، خطاها را برطرف کرده و دوباره درون‌بُرد کنید."
#: frappe/twofactor.py:286
msgid "Please click on the following link and follow the instructions on the page. {0}"
@ -19648,7 +19648,7 @@ msgstr "لطفاً از یک فیلتر جستجوی معتبر LDAP استفا
#: frappe/templates/emails/file_backup_notification.html:4
msgid "Please use following links to download file backup."
msgstr ""
msgstr "لطفا برای دانلود فایل پشتیبان از لینک‌های زیر استفاده کنید."
#: frappe/utils/password.py:217
msgid "Please visit https://frappecloud.com/docs/sites/migrate-an-existing-site#encryption-key for more information."
@ -24281,7 +24281,7 @@ msgstr "نمایش ردیابی"
#. Chart'
#: frappe/desk/doctype/dashboard_chart/dashboard_chart.json
msgid "Show Values over Chart"
msgstr ""
msgstr "نمایش مقادیر روی نمودار"
#: frappe/public/js/frappe/data_import/import_preview.js:204
msgid "Show Warnings"
@ -24524,7 +24524,7 @@ msgstr "حجم (مگابایت)"
#: frappe/public/js/frappe/file_uploader/FileUploader.vue:629
msgid "Size exceeds the maximum allowed file size."
msgstr ""
msgstr "حجم فایل از حداکثر حجم مجاز بیشتر است."
#: frappe/public/js/frappe/widgets/onboarding_widget.js:82
#: frappe/public/js/onboarding_tours/onboarding_tours.js:18
@ -25348,7 +25348,7 @@ msgstr "پاسخ دیگری را ثبت کنید"
#. Label of the button_label (Data) field in DocType 'Web Form'
#: frappe/website/doctype/web_form/web_form.json
msgid "Submit button label"
msgstr ""
msgstr "برچسب دکمه ارسال"
#. Label of the submit_on_creation (Check) field in DocType 'Auto Repeat'
#: frappe/automation/doctype/auto_repeat/auto_repeat.json
@ -26610,7 +26610,7 @@ msgstr "این سند پس از ارسال ایمیل اصلاح شده است."
#: frappe/public/js/frappe/form/form.js:1317
msgid "This document has unsaved changes which might not appear in final PDF. <br> Consider saving the document before printing."
msgstr ""
msgstr "این سند دارای تغییرات ذخیره‌نشده است که ممکن است در فایل PDF نهایی نمایش داده نشوند. <br> قبل از چاپ، سند را ذخیره کنید."
#: frappe/public/js/frappe/form/form.js:1105
msgid "This document is already amended, you cannot ammend it again"
@ -26649,7 +26649,7 @@ msgstr "این فایل به یک سند محافظت شده پیوست شده
#: frappe/public/js/frappe/file_uploader/FilePreview.vue:76
msgid "This file is public and can be accessed by anyone, even without logging in. Mark it private to limit access."
msgstr ""
msgstr "این فایل عمومی است و هر کسی می‌تواند به آن دسترسی داشته باشد، حتی بدون ورود به سیستم. برای محدود کردن دسترسی، آن را خصوصی علامت‌گذاری کنید."
#: frappe/core/doctype/file/file.js:20
msgid "This file is public. It can be accessed without authentication."
@ -26754,7 +26754,7 @@ msgstr "این سایت در حالت توسعه دهنده در حال اجرا
#: frappe/www/attribution.html:11
msgid "This software is built on top of many open source packages."
msgstr ""
msgstr "این نرم‌افزار بر پایه بسیاری از بسته‌های نرم‌افزاری متن‌باز ساخته شده است."
#: frappe/website/doctype/web_page/web_page.js:71
msgid "This title will be used as the title of the webpage as well as in meta tags"
@ -30107,7 +30107,7 @@ msgstr "همچنین می‌توانید این {0} را در مرورگر خو
#: frappe/templates/emails/user_invitation_expired.html:8
msgid "You can ask your team to resend the invitation if you'd still like to join."
msgstr ""
msgstr "اگر هنوز مایل به عضویت هستید، می‌توانید از تیم خود بخواهید که دعوت‌نامه را دوباره ارسال کند."
#: frappe/core/page/permission_manager/permission_manager_help.html:17
msgid "You can change Submitted documents by cancelling them and then, amending them."
@ -30250,7 +30250,7 @@ msgstr ""
#: frappe/database/query.py:810
msgid "You do not have permission to access field: {0}"
msgstr ""
msgstr "شما اجازه دسترسی به فیلد را ندارید: {0}"
#: frappe/desk/query_report.py:934
msgid "You do not have permission to access {0}: {1}."
@ -30459,15 +30459,15 @@ msgstr "شما هدایت خواهید شد به:"
#: frappe/core/doctype/user_invitation/user_invitation.py:113
msgid "You've been invited to join {0}"
msgstr ""
msgstr "از شما دعوت شده است تا به {0} بپیوندید"
#: frappe/templates/emails/user_invitation.html:5
msgid "You've been invited to join {0}."
msgstr ""
msgstr "از شما دعوت شده است تا به {0} بپیوندید."
#: frappe/public/js/frappe/desk.js:547
msgid "You've logged in as another user from another tab. Refresh this page to continue using system."
msgstr ""
msgstr "شما به عنوان یک کاربر دیگر از یک تب دیگر وارد سیستم شده‌اید. برای ادامه استفاده از سیستم، این صفحه را رفرش کنید."
#: frappe/public/js/frappe/ui/toolbar/about.js:11
msgid "YouTube"
@ -30536,11 +30536,11 @@ msgstr "فرم شما با موفقیت به روز شد"
#: frappe/templates/emails/user_invitation_cancelled.html:5
msgid "Your invitation to join {0} has been cancelled by the site administrator."
msgstr ""
msgstr "دعوت شما برای عضویت {0} توسط مدیر سایت لغو شده است."
#: frappe/templates/emails/user_invitation_expired.html:5
msgid "Your invitation to join {0} has expired."
msgstr ""
msgstr "دعوت شما برای عضویت {0} منقضی شده است."
#: frappe/templates/emails/new_user.html:6
msgid "Your login id is"
@ -30566,7 +30566,7 @@ msgstr "پرسمان شما دریافت شد. ما به زودی پاسخ خو
#: frappe/desk/query_report.py:342 frappe/desk/reportview.py:402
msgid "Your report is being generated in the background. You will receive an email on {0} with a download link once it is ready."
msgstr ""
msgstr "گزارش شما در پس‌زمینه در حال تولید است. به محض آماده شدن، ایمیلی حاوی لینک دانلود در {0} دریافت خواهید کرد."
#: frappe/app.py:377
msgid "Your session has expired, please login again to continue."
@ -31858,7 +31858,7 @@ msgstr "{0} رکورد برون‌بُرد خواهد شد"
#: frappe/public/js/frappe/form/footer/version_timeline_content_builder.js:313
msgid "{0} removed 1 row from {1}"
msgstr ""
msgstr "{0} ۱ ردیف از {1} حذف کرد"
#: frappe/public/js/frappe/form/footer/form_timeline.js:420
msgctxt "Form timeline"
@ -31871,7 +31871,7 @@ msgstr "{0} تخصیص خود را حذف کرد."
#: frappe/public/js/frappe/form/footer/version_timeline_content_builder.js:291
msgid "{0} removed {1} rows from {2}"
msgstr ""
msgstr "{0} {1} ردیف از {2} حذف کرد"
#: frappe/public/js/frappe/roles_editor.js:64
msgid "{0} role does not have permission on any doctype"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-11-30 09:34+0000\n"
"PO-Revision-Date: 2025-12-03 15:04\n"
"PO-Revision-Date: 2025-12-07 17:11\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Slovenian\n"
"MIME-Version: 1.0\n"
@ -775,40 +775,42 @@ msgstr "Polje z imenom {0} že obstaja v {1}"
#: frappe/core/doctype/file/file.py:269
msgid "A file with same name {} already exists"
msgstr ""
msgstr "Datoteka z istim imenom {} že obstaja"
#. Description of the 'Scopes' (Text) field in DocType 'OAuth Client'
#: frappe/integrations/doctype/oauth_client/oauth_client.json
msgid "A list of resources which the Client App will have access to after the user allows it.<br> e.g. project"
msgstr ""
msgstr "Seznam virov, do katerih bo imela odjemalska aplikacija dostop, ko uporabnik to dovoli.<br> npr. projekt"
#: frappe/templates/emails/new_user.html:5
msgid "A new account has been created for you at {0}"
msgstr ""
msgstr "Za vas je bil ustvarjen nov račun na {0}"
#: frappe/automation/doctype/auto_repeat/auto_repeat.py:431
msgid "A recurring {0} {1} has been created for you via Auto Repeat {2}."
msgstr ""
msgstr "Ponavljajoči se {0} {1} je bil za vas ustvarjen prek storitve Samodejno ponavljanje {2}."
#. Description of the 'Symbol' (Data) field in DocType 'Currency'
#: frappe/geo/doctype/currency/currency.json
msgid "A symbol for this currency. For e.g. $"
msgstr ""
msgstr "Simbol za to valuto. Npr. $"
#: frappe/printing/doctype/print_format_field_template/print_format_field_template.py:49
msgid "A template already exists for field {0} of {1}"
msgstr ""
msgstr "Predloga za polje {0} od {1} že obstaja"
#. Description of the 'Software Version' (Data) field in DocType 'OAuth Client'
#: frappe/integrations/doctype/oauth_client/oauth_client.json
msgid "A version identifier string for the client software.\n"
"<br>\n"
"The value of the should change on any update of the client software with the same Software ID."
msgstr ""
msgstr "Niz identifikatorja različice za odjemalsko programsko opremo.\n"
"<br>\n"
"Vrednost se mora spremeniti ob vsaki posodobitvi odjemalske programske opreme z istim identifikatorjem programske opreme."
#: frappe/utils/password_strength.py:169
msgid "A word by itself is easy to guess."
msgstr ""
msgstr "Besedo samo po sebi je enostavno uganiti."
#. Option for the 'PDF Page Size' (Select) field in DocType 'Print Settings'
#: frappe/printing/doctype/print_settings/print_settings.json
@ -883,7 +885,7 @@ msgstr "Končna točka API"
#. Label of the api_endpoint_args (Code) field in DocType 'Social Login Key'
#: frappe/integrations/doctype/social_login_key/social_login_key.json
msgid "API Endpoint Args"
msgstr ""
msgstr "Končne točke API Args"
#: frappe/integrations/doctype/social_login_key/social_login_key.py:102
msgid "API Endpoint Args should be valid JSON"
@ -1579,7 +1581,7 @@ msgstr ""
#: frappe/contacts/doctype/address/address.py:205
msgid "Addresses"
msgstr ""
msgstr "Naslovi"
#. Name of a report
#: frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.json
@ -2005,7 +2007,7 @@ msgstr ""
#. Label of the allow_events_in_timeline (Check) field in DocType 'DocType'
#: frappe/core/doctype/doctype/doctype.json
msgid "Allow events in timeline"
msgstr ""
msgstr "Dovoli dogodke na časovnici"
#. Label of the allow_in_quick_entry (Check) field in DocType 'DocField'
#. Label of the allow_in_quick_entry (Check) field in DocType 'Custom Field'
@ -2020,12 +2022,12 @@ msgstr "Dovoli v Hitrem Vnosu"
#. Label of the allow_incomplete (Check) field in DocType 'Web Form'
#: frappe/website/doctype/web_form/web_form.json
msgid "Allow incomplete forms"
msgstr ""
msgstr "Dovoli nepopolne obrazce"
#. Label of the allow_multiple (Check) field in DocType 'Web Form'
#: frappe/website/doctype/web_form/web_form.json
msgid "Allow multiple responses"
msgstr ""
msgstr "Dovoli več odgovorov"
#. Label of the allow_on_submit (Check) field in DocType 'DocField'
#. Label of the allow_on_submit (Check) field in DocType 'Custom Field'
@ -2040,13 +2042,13 @@ msgstr "Dovoli ob Oddaji"
#. Settings'
#: frappe/core/doctype/system_settings/system_settings.json
msgid "Allow only one session per user"
msgstr ""
msgstr "Dovoli samo eno sejo na uporabnika"
#. Label of the allow_page_break_inside_tables (Check) field in DocType 'Print
#. Settings'
#: frappe/printing/doctype/print_settings/print_settings.json
msgid "Allow page break inside tables"
msgstr ""
msgstr "Dovoli prelom strani znotraj tabel"
#. Label of the allow_print (Check) field in DocType 'Web Form'
#: frappe/website/doctype/web_form/web_form.json
@ -2055,27 +2057,27 @@ msgstr "Dovoli Tiskanje"
#: frappe/desk/page/setup_wizard/setup_wizard.js:431
msgid "Allow recording my first session to improve user experience"
msgstr ""
msgstr "Dovoli snemanje moje prve seje za izboljšanje uporabniške izkušnje"
#. Description of the 'Allow incomplete forms' (Check) field in DocType 'Web
#. Form'
#: frappe/website/doctype/web_form/web_form.json
msgid "Allow saving if mandatory fields are not filled"
msgstr ""
msgstr "Dovoli shranjevanje, če obvezna polja niso izpolnjena"
#: frappe/desk/page/setup_wizard/setup_wizard.js:424
msgid "Allow sending usage data for improving applications"
msgstr ""
msgstr "Dovoli pošiljanje podatkov o uporabi za izboljšanje aplikacij"
#. Description of the 'Login After' (Int) field in DocType 'User'
#: frappe/core/doctype/user/user.json
msgid "Allow user to login only after this hour (0-24)"
msgstr ""
msgstr "Dovoli uporabniku prijavo šele po tej uri (024)"
#. Description of the 'Login Before' (Int) field in DocType 'User'
#: frappe/core/doctype/user/user.json
msgid "Allow user to login only before this hour (0-24)"
msgstr ""
msgstr "Dovoli uporabniku prijavo samo pred to uro (024)"
#. Description of the 'Login with email link' (Check) field in DocType 'System
#. Settings'
@ -2408,11 +2410,11 @@ msgstr ""
#: frappe/email/doctype/email_account/email_account.json
#: frappe/email/doctype/imap_folder/imap_folder.json
msgid "Append To"
msgstr ""
msgstr "Dodaj k"
#: frappe/email/doctype/email_account/email_account.py:202
msgid "Append To can be one of {0}"
msgstr ""
msgstr "Dodaj k je lahko eden od {0}"
#. Description of the 'Append To' (Link) field in DocType 'Email Account'
#: frappe/email/doctype/email_account/email_account.json
@ -2633,7 +2635,7 @@ msgstr ""
#: frappe/core/doctype/document_naming_rule/document_naming_rule.js:16
#: frappe/core/doctype/user_permission/user_permission_list.js:165
msgid "Are you sure?"
msgstr ""
msgstr "Ste prepričani?"
#. Label of the arguments (Code) field in DocType 'RQ Job'
#: frappe/core/doctype/rq_job/rq_job.json
@ -2960,7 +2962,7 @@ msgstr ""
#. Name of a DocType
#: frappe/core/doctype/audit_trail/audit_trail.json
msgid "Audit Trail"
msgstr ""
msgstr "Revizijska sled"
#. Label of the auth_url_data (Code) field in DocType 'Social Login Key'
#: frappe/integrations/doctype/social_login_key/social_login_key.json
@ -3054,7 +3056,7 @@ msgstr ""
#. Label of the authorize_url (Data) field in DocType 'Social Login Key'
#: frappe/integrations/doctype/social_login_key/social_login_key.json
msgid "Authorize URL"
msgstr ""
msgstr "Avtoriziraj URL"
#. Option for the 'Status' (Select) field in DocType 'Integration Request'
#: frappe/integrations/doctype/integration_request/integration_request.json
@ -3096,7 +3098,7 @@ msgstr "Samodejno Ponavljanje"
#. Name of a DocType
#: frappe/automation/doctype/auto_repeat_day/auto_repeat_day.json
msgid "Auto Repeat Day"
msgstr ""
msgstr "Dan samodejnega ponavljanja"
#: frappe/automation/doctype/auto_repeat/auto_repeat.py:173
msgid "Auto Repeat Day{0} {1} has been repeated."
@ -3190,13 +3192,13 @@ msgstr ""
#. 'Communication'
#: frappe/core/doctype/communication/communication.json
msgid "Automated Message"
msgstr ""
msgstr "Samodejno sporočilo"
#. Option for the 'Desk Theme' (Select) field in DocType 'User'
#: frappe/core/doctype/user/user.json
#: frappe/public/js/frappe/ui/theme_switcher.js:69
msgid "Automatic"
msgstr ""
msgstr "Samodejno"
#: frappe/email/doctype/email_account/email_account.py:772
msgid "Automatic Linking can be activated only for one Email Account."
@ -3275,7 +3277,7 @@ msgstr "Odlično, zdaj pa poskusite sami ustvariti vnos"
#. Option for the 'Navbar Style' (Select) field in DocType 'Desktop Settings'
#: frappe/desk/doctype/desktop_settings/desktop_settings.json
msgid "Awesomebar"
msgstr ""
msgstr "Awesomebar"
#: frappe/public/js/frappe/utils/number_systems.js:9
msgctxt "Number system"
@ -3385,7 +3387,7 @@ msgstr "Slika Ozadja"
#. Label of a chart in the System Workspace
#: frappe/core/workspace/system/system.json
msgid "Background Job Activity"
msgstr ""
msgstr "Dejavnost opravila v ozadju"
#. Label of a Link in the Build Workspace
#. Label of the background_jobs_section (Section Break) field in DocType
@ -3400,16 +3402,16 @@ msgstr "Ozadna Dela"
#. Report'
#: frappe/desk/doctype/system_health_report/system_health_report.json
msgid "Background Jobs Check"
msgstr ""
msgstr "Preverjanje delovnih mest v ozadju"
#. Label of the background_jobs_queue (Autocomplete) field in DocType 'Webhook'
#: frappe/integrations/doctype/webhook/webhook.json
msgid "Background Jobs Queue"
msgstr ""
msgstr "Čakalna vrsta opravil v ozadju"
#: frappe/public/js/frappe/list/bulk_operations.js:87
msgid "Background Print (required for >25 documents)"
msgstr ""
msgstr "Tisk v ozadju (potrebno za >25 dokumentov)"
#. Label of the background_workers (Section Break) field in DocType 'System
#. Settings'
@ -3418,7 +3420,7 @@ msgstr ""
#: frappe/core/doctype/system_settings/system_settings.json
#: frappe/desk/doctype/system_health_report/system_health_report.json
msgid "Background Workers"
msgstr ""
msgstr "Delavci v ozadju"
#: frappe/desk/page/backups/backups.js:28
msgid "Backup Encryption Key"
@ -3578,26 +3580,26 @@ msgstr ""
#. Option for the 'DocType Event' (Select) field in DocType 'Server Script'
#: frappe/core/doctype/server_script/server_script.json
msgid "Before Submit"
msgstr ""
msgstr "Pred Oddajo"
#. Option for the 'DocType Event' (Select) field in DocType 'Server Script'
#: frappe/core/doctype/server_script/server_script.json
msgid "Before Validate"
msgstr ""
msgstr "Pred Potrditvijo"
#. Option for the 'Level' (Select) field in DocType 'Help Article'
#: frappe/website/doctype/help_article/help_article.json
msgid "Beginner"
msgstr ""
msgstr "Začetnik"
#: frappe/public/js/frappe/form/link_selector.js:29
msgid "Beginning with"
msgstr ""
msgstr "Začenši z"
#. Label of the beta (Check) field in DocType 'DocType'
#: frappe/core/doctype/doctype/doctype.json
msgid "Beta"
msgstr ""
msgstr "Beta"
#: frappe/utils/password_strength.py:73
msgid "Better add a few more letters or another word"
@ -3605,7 +3607,7 @@ msgstr ""
#: frappe/public/js/frappe/ui/filters/filter.js:27
msgid "Between"
msgstr ""
msgstr "Med"
#. Option for the 'Address Type' (Select) field in DocType 'Address'
#: frappe/contacts/doctype/address/address.json
@ -3781,7 +3783,7 @@ msgstr ""
#. Name of a Workspace
#: frappe/core/workspace/build/build.json
msgid "Build"
msgstr ""
msgstr "Zgradi"
#. Description of a Card Break in the Build Workspace
#: frappe/core/workspace/build/build.json
@ -3790,45 +3792,45 @@ msgstr ""
#: frappe/workflow/doctype/workflow/workflow_list.js:18
msgid "Build {0}"
msgstr ""
msgstr "+ {0}"
#: frappe/templates/includes/footer/footer_powered.html:1
msgid "Built on {0}"
msgstr ""
msgstr "Zgrajeno na {0}"
#. Label of the bulk_actions (Check) field in DocType 'User'
#: frappe/core/doctype/user/user.json
msgid "Bulk Actions"
msgstr ""
msgstr "Množična dejanja"
#: frappe/core/doctype/user_permission/user_permission_list.js:142
msgid "Bulk Delete"
msgstr ""
msgstr "Množično brisanje"
#: frappe/public/js/frappe/list/bulk_operations.js:321
msgid "Bulk Edit"
msgstr ""
msgstr "Množično urejanje"
#: frappe/public/js/frappe/form/grid.js:1211
msgid "Bulk Edit {0}"
msgstr ""
msgstr "Množično urejanje {0}"
#: frappe/desk/reportview.py:643
msgid "Bulk Operation Failed"
msgstr ""
msgstr "Množična operacija ni uspela"
#: frappe/desk/reportview.py:647
msgid "Bulk Operation Successful"
msgstr ""
msgstr "Množična operacija je uspešna"
#: frappe/public/js/frappe/list/bulk_operations.js:131
msgid "Bulk PDF Export"
msgstr ""
msgstr "Množično izvažanje PDF"
#. Name of a DocType
#: frappe/desk/doctype/bulk_update/bulk_update.json
msgid "Bulk Update"
msgstr ""
msgstr "Množična posodobitev"
#: frappe/model/workflow.py:310
msgid "Bulk approval only support up to 500 documents."
@ -3853,17 +3855,17 @@ msgstr ""
#: frappe/custom/doctype/custom_field/custom_field.json
#: frappe/custom/doctype/customize_form_field/customize_form_field.json
msgid "Button"
msgstr ""
msgstr "Gumb"
#. Label of the button_gradients (Check) field in DocType 'Website Theme'
#: frappe/website/doctype/website_theme/website_theme.json
msgid "Button Gradients"
msgstr ""
msgstr "Gradienti gumbov"
#. Label of the button_rounded_corners (Check) field in DocType 'Website Theme'
#: frappe/website/doctype/website_theme/website_theme.json
msgid "Button Rounded Corners"
msgstr ""
msgstr "Zaobljeni vogali gumba"
#. Label of the button_shadows (Check) field in DocType 'Website Theme'
#: frappe/website/doctype/website_theme/website_theme.json
@ -3921,7 +3923,7 @@ msgstr ""
#: frappe/templates/print_formats/standard_macros.html:220
msgid "CANCELLED"
msgstr ""
msgstr "ODKLICANO"
#. Label of the cc (Code) field in DocType 'Communication'
#. Label of the cc (Code) field in DocType 'Notification Recipient'
@ -4129,7 +4131,7 @@ msgstr ""
#: frappe/public/js/frappe/model/indicator.js:78
#: frappe/public/js/frappe/ui/filters/filter.js:540
msgid "Cancelled"
msgstr ""
msgstr "Preklicano"
#: frappe/core/doctype/deleted_document/deleted_document.py:52
msgid "Cancelled Document restored as Draft"
@ -4392,24 +4394,24 @@ msgstr "Kartice"
#: frappe/public/js/frappe/views/interaction.js:72
#: frappe/website/doctype/help_article/help_article.json
msgid "Category"
msgstr ""
msgstr "Kategorija"
#. Label of the category_description (Text) field in DocType 'Help Category'
#: frappe/website/doctype/help_category/help_category.json
msgid "Category Description"
msgstr ""
msgstr "Opis Kategorije"
#. Label of the category_name (Data) field in DocType 'Help Category'
#: frappe/website/doctype/help_category/help_category.json
msgid "Category Name"
msgstr ""
msgstr "Ime Kategorije"
#. Option for the 'Align' (Select) field in DocType 'Letter Head'
#. Option for the 'Text Align' (Select) field in DocType 'Web Page'
#: frappe/printing/doctype/letter_head/letter_head.json
#: frappe/website/doctype/web_page/web_page.json
msgid "Center"
msgstr ""
msgstr "Center"
#: frappe/core/page/permission_manager/permission_manager_help.html:16
msgid "Certain documents, like an Invoice, should not be changed once final. The final state for such documents is called Submitted. You can restrict which roles can Submit."
@ -4458,7 +4460,7 @@ msgstr ""
#. Label of the changed_at (Datetime) field in DocType 'Permission Log'
#: frappe/core/doctype/permission_log/permission_log.json
msgid "Changed at"
msgstr ""
msgstr "Spremenjeno"
#. Label of the changed_by (Link) field in DocType 'Permission Log'
#: frappe/core/doctype/permission_log/permission_log.json
@ -4473,7 +4475,7 @@ msgstr ""
#. Label of the changed_values (HTML) field in DocType 'Permission Log'
#: frappe/core/doctype/permission_log/permission_log.json
msgid "Changes"
msgstr ""
msgstr "Spremembe"
#: frappe/email/doctype/email_domain/email_domain.js:5
msgid "Changing any setting will reflect on all the email accounts associated with this domain."
@ -4518,25 +4520,25 @@ msgstr ""
#. Label of the source (Link) field in DocType 'Dashboard Chart'
#: frappe/desk/doctype/dashboard_chart/dashboard_chart.json
msgid "Chart Source"
msgstr ""
msgstr "Vir Grafikona"
#. Label of the chart_type (Select) field in DocType 'Dashboard Chart'
#: frappe/desk/doctype/dashboard_chart/dashboard_chart.json
#: frappe/public/js/frappe/views/reports/report_view.js:510
msgid "Chart Type"
msgstr ""
msgstr "Tip Grafikona"
#. Label of the charts (Table) field in DocType 'Dashboard'
#. Label of the charts (Table) field in DocType 'Workspace'
#: frappe/desk/doctype/dashboard/dashboard.json
#: frappe/desk/doctype/workspace/workspace.json
msgid "Charts"
msgstr ""
msgstr "Grafikoni"
#. Option for the 'Type' (Select) field in DocType 'Communication'
#: frappe/core/doctype/communication/communication.json
msgid "Chat"
msgstr ""
msgstr "Klepet"
#. Option for the 'Type' (Select) field in DocType 'DocField'
#. Option for the 'Fieldtype' (Select) field in DocType 'Report Column'
@ -4553,7 +4555,7 @@ msgstr ""
#: frappe/website/doctype/web_form_field/web_form_field.json
#: frappe/website/doctype/web_template_field/web_template_field.json
msgid "Check"
msgstr ""
msgstr "Preveri"
#: frappe/integrations/doctype/webhook/webhook.py:99
msgid "Check Request URL"
@ -4611,12 +4613,12 @@ msgstr ""
#. Label of the child_doctype (Data) field in DocType 'Form Tour Step'
#: frappe/desk/doctype/form_tour_step/form_tour_step.json
msgid "Child Doctype"
msgstr ""
msgstr "Podrejeni Doctype"
#. Label of the child (Check) field in DocType 'Workspace Sidebar Item'
#: frappe/desk/doctype/workspace_sidebar_item/workspace_sidebar_item.json
msgid "Child Item"
msgstr ""
msgstr "Podrejeni Artikel"
#: frappe/core/doctype/doctype/doctype.py:1647
msgid "Child Table {0} for field {1} must be virtual"
@ -4664,34 +4666,34 @@ msgstr ""
#: frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.py:39
#: frappe/website/doctype/contact_us_settings/contact_us_settings.json
msgid "City"
msgstr ""
msgstr "Mesto"
#. Label of the city (Data) field in DocType 'Address'
#: frappe/contacts/doctype/address/address.json
msgid "City/Town"
msgstr ""
msgstr "Mesto/Kraj"
#: frappe/core/doctype/recorder/recorder_list.js:12
#: frappe/public/js/frappe/form/controls/attach.js:16
msgid "Clear"
msgstr ""
msgstr "Počisti"
#: frappe/public/js/frappe/views/communication.js:429
msgid "Clear & Add Template"
msgstr ""
msgstr "Počisti & Dodaj Predlogo"
#: frappe/public/js/frappe/views/communication.js:105
msgid "Clear & Add template"
msgstr ""
msgstr "Počisti & Dodaj Predlogo"
#: frappe/public/js/frappe/form/controls/multiselect_list.js:6
msgid "Clear All"
msgstr ""
msgstr "Počisti vse"
#: frappe/public/js/frappe/list/list_view.js:2122
msgctxt "Button in list view actions menu"
msgid "Clear Assignment"
msgstr ""
msgstr "Počisti dodelitev"
#: frappe/public/js/frappe/ui/keyboard.js:287
msgid "Clear Cache and Reload"
@ -4732,7 +4734,7 @@ msgstr ""
#: frappe/website/doctype/web_form/templates/web_form.html:154
msgid "Click here"
msgstr ""
msgstr "Klikni tukaj"
#: frappe/public/js/frappe/file_uploader/FileUploader.vue:539
msgid "Click on a file to select it."
@ -4892,7 +4894,7 @@ msgstr ""
#: frappe/public/js/frappe/ui/messages.js:251
#: frappe/website/js/bootstrap-4.js:24
msgid "Close"
msgstr ""
msgstr "Zapri"
#. Label of the close_condition (Code) field in DocType 'Assignment Rule'
#: frappe/automation/doctype/assignment_rule/assignment_rule.json
@ -4911,7 +4913,7 @@ msgstr ""
#: frappe/core/doctype/communication/communication.json
#: frappe/desk/doctype/event/event.json frappe/desk/doctype/todo/todo.json
msgid "Closed"
msgstr ""
msgstr "Zaprto"
#: frappe/templates/discussions/comment_box.html:25
#: frappe/templates/discussions/reply_section.html:53
@ -4930,7 +4932,7 @@ msgstr ""
#: frappe/geo/doctype/country/country.json
#: frappe/integrations/doctype/oauth_client/oauth_client.json
msgid "Code"
msgstr ""
msgstr "Koda"
#. Label of the code_challenge (Data) field in DocType 'OAuth Authorization
#. Code'
@ -5024,7 +5026,7 @@ msgstr ""
#: frappe/website/doctype/social_link_settings/social_link_settings.json
#: frappe/website/doctype/web_form_field/web_form_field.json
msgid "Color"
msgstr ""
msgstr "Barva"
#. Label of the column (Data) field in DocType 'Recorder Suggested Index'
#: frappe/core/doctype/recorder_suggested_index/recorder_suggested_index.json
@ -5032,19 +5034,19 @@ msgstr ""
#: frappe/public/js/form_builder/components/Section.vue:270
#: frappe/public/js/print_format_builder/ConfigureColumns.vue:8
msgid "Column"
msgstr ""
msgstr "Stolpec"
#: frappe/core/doctype/report/boilerplate/controller.py:28
msgid "Column 1"
msgstr ""
msgstr "Stolpec 1"
#: frappe/core/doctype/report/boilerplate/controller.py:33
msgid "Column 2"
msgstr ""
msgstr "Stolpec 2"
#: frappe/desk/doctype/kanban_board/kanban_board.py:84
msgid "Column <b>{0}</b> already exist."
msgstr ""
msgstr "Stolpec <b>{0}</b> že obstaja."
#. Option for the 'Type' (Select) field in DocType 'DocField'
#. Option for the 'Field Type' (Select) field in DocType 'Custom Field'
@ -5057,17 +5059,17 @@ msgstr ""
#: frappe/website/doctype/web_form_field/web_form_field.json
#: frappe/website/doctype/web_template_field/web_template_field.json
msgid "Column Break"
msgstr ""
msgstr "Prelom Stolpca"
#: frappe/core/doctype/data_export/exporter.py:140
msgid "Column Labels:"
msgstr ""
msgstr "Oznake Stolpcev:"
#. Label of the column_name (Data) field in DocType 'Kanban Board Column'
#: frappe/core/doctype/data_export/exporter.py:25
#: frappe/desk/doctype/kanban_board_column/kanban_board_column.json
msgid "Column Name"
msgstr ""
msgstr "Ime Stolpca"
#: frappe/desk/doctype/kanban_board/kanban_board.py:45
msgid "Column Name cannot be empty"
@ -5115,7 +5117,7 @@ msgstr ""
#. Option for the 'PDF Page Size' (Select) field in DocType 'Print Settings'
#: frappe/printing/doctype/print_settings/print_settings.json
msgid "Comm10E"
msgstr ""
msgstr "Comm10E"
#. Name of a DocType
#. Option for the 'Comment Type' (Select) field in DocType 'Comment'
@ -5125,7 +5127,7 @@ msgstr ""
#: frappe/public/js/frappe/form/sidebar/assign_to.js:237
#: frappe/templates/includes/comments/comments.html:34
msgid "Comment"
msgstr ""
msgstr "Komentar"
#. Label of the comment_by (Data) field in DocType 'Comment'
#: frappe/core/doctype/comment/comment.json
@ -8426,7 +8428,7 @@ msgstr ""
#: frappe/public/js/frappe/form/grid_row_form.js:42
msgid "ESC"
msgstr ""
msgstr "ESC"
#. Option for the 'Comment Type' (Select) field in DocType 'Comment'
#: frappe/core/doctype/comment/comment.json

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-11-30 09:34+0000\n"
"PO-Revision-Date: 2025-12-02 14:59\n"
"PO-Revision-Date: 2025-12-07 17:11\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Swedish\n"
"MIME-Version: 1.0\n"
@ -3796,7 +3796,7 @@ msgstr "Skapa {0}"
#: frappe/templates/includes/footer/footer_powered.html:1
msgid "Built on {0}"
msgstr "Skapad av{0}"
msgstr "Skapad av {0}"
#. Label of the bulk_actions (Check) field in DocType 'User'
#: frappe/core/doctype/user/user.json

View file

@ -200,8 +200,7 @@ class DatabaseQuery:
query = frappe.qb.get_query(**kwargs)
if not run:
# Return the SQL query string instead of executing
return str(query.get_sql())
return query
# Run the query
if pluck:

View file

@ -1900,14 +1900,18 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
get_search_params() {
let search_params = new URLSearchParams();
this.get_filters_for_args().forEach((filter) => {
if (filter[2] === "=") {
search_params.append(filter[1], filter[3]);
} else {
search_params.append(filter[1], JSON.stringify([filter[2], filter[3]]));
}
const doctype = filter[0];
const field = filter[1];
const operator = filter[2];
const value = filter[3];
const query_key = doctype === this.doctype ? field : `${doctype}.${field}`;
const query_value = operator === "=" ? value : JSON.stringify([operator, value]);
search_params.append(query_key, query_value);
});
return search_params;
}

View file

@ -161,11 +161,11 @@ frappe.ui.Sidebar = class Sidebar {
let match = false;
const that = this;
$(".item-anchor").each(function () {
let href = $(this).attr("href")?.split("?")[0];
let href = decodeURIComponent($(this).attr("href")?.split("?")[0]);
const path = decodeURIComponent(window.location.pathname);
// Match only if path equals href or starts with it followed by "/" or end of string
const isActive = new RegExp(`^${href}(?:/|$)`).test(path);
const isActive = href === path;
if (href && isActive) {
match = true;
if (that.active_item) that.active_item.removeClass("active-sidebar");
@ -445,7 +445,7 @@ frappe.ui.Sidebar = class Sidebar {
if (route.length == 2) {
workspace_title = this.get_correct_workspace_sidebars(route[1]);
} else {
workspace_title = this.get_correct_workspace_sidebars(route);
workspace_title = this.get_correct_workspace_sidebars(route[0]);
}
let module_name = workspace_title[0];
if (module_name) {

View file

@ -54,14 +54,16 @@ frappe.ui.sidebar_item.TypeLink = class SidebarItem {
});
}
}
return path;
if (path) {
return encodeURI(path);
}
}
prepare() {}
make() {
this.path = this.get_path();
this.set_suffix();
if (!this.item.icon && !(this.item.child && this.item.parent.indent)) {
this.item.icon = "list-alt";
this.item.icon = "list";
}
this.wrapper = $(
frappe.render_template("sidebar_item", {

View file

@ -1754,10 +1754,19 @@ Object.assign(frappe.utils, {
// don't remove unless patch is created to convert all existing filters from object to array
// backward compatibility
if (Array.isArray(filters_json)) {
let filter = {};
filters_json.forEach((arr) => {
filter[arr[1]] = [arr[2], arr[3]];
});
let filter = filters_json.reduce((acc, filter) => {
const field = filter[1];
const value = [filter[2], filter[3]];
// if we have multiple filters for the same field,
// we convert it into an array
if (acc[field]) {
acc[field].push(value);
} else {
acc[field] = [value];
}
return acc;
}, {});
return filter || [];
}
return filters_json || [];

View file

@ -1047,28 +1047,32 @@ class TestDBQuery(IntegrationTestCase):
self.assertIn("count", result[0])
def test_coalesce_with_in_ops(self):
self.assertNotIn("IF", frappe.get_all("User", {"first_name": ("in", ["a", "b"])}, run=0))
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("in", ["a", None])}, run=0))
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("in", ["a", ""])}, run=0))
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("in", [])}, run=0))
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("not in", ["a"])}, run=0))
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("not in", [])}, run=0))
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("not in", [""])}, run=0))
self.assertNotIn("IF", frappe.get_all("User", {"first_name": ("in", ["a", "b"])}, run=0).get_sql())
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("in", ["a", None])}, run=0).get_sql())
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("in", ["a", ""])}, run=0).get_sql())
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("in", [])}, run=0).get_sql())
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("not in", ["a"])}, run=0).get_sql())
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("not in", [])}, run=0).get_sql())
self.assertIn("IFNULL", frappe.get_all("User", {"first_name": ("not in", [""])}, run=0).get_sql())
# primary key is never nullable
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", ["a", None])}, run=0))
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", ["a", ""])}, run=0))
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", (""))}, run=0))
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", ())}, run=0))
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", ["a", None])}, run=0).get_sql())
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", ["a", ""])}, run=0).get_sql())
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", (""))}, run=0).get_sql())
self.assertNotIn("IFNULL", frappe.get_all("User", {"name": ("in", ())}, run=0).get_sql())
def test_coalesce_with_datetime_ops(self):
self.assertNotIn("IFNULL", frappe.get_all("User", {"last_active": (">", "2022-01-01")}, run=0))
self.assertNotIn("IFNULL", frappe.get_all("User", {"creation": ("<", "2022-01-01")}, run=0))
self.assertNotIn(
"IFNULL", frappe.get_all("User", {"last_active": (">", "2022-01-01")}, run=0).get_sql()
)
self.assertNotIn("IFNULL", frappe.get_all("User", {"creation": ("<", "2022-01-01")}, run=0).get_sql())
self.assertNotIn(
"IFNULL",
frappe.get_all("User", {"last_active": ("between", ("2022-01-01", "2023-01-01"))}, run=0),
frappe.get_all(
"User", {"last_active": ("between", ("2022-01-01", "2023-01-01"))}, run=0
).get_sql(),
)
self.assertIn("IFNULL", frappe.get_all("User", {"last_active": ("<", "2022-01-01")}, run=0))
self.assertIn("IFNULL", frappe.get_all("User", {"last_active": ("<", "2022-01-01")}, run=0).get_sql())
def test_ambiguous_linked_tables(self):
from frappe.desk.reportview import get
@ -1145,16 +1149,16 @@ class TestDBQuery(IntegrationTestCase):
self.assertEqual(count[1], frappe.db.count("Language"))
def test_ifnull_none(self):
query = frappe.get_all("DocField", {"fieldname": None}, run=0)
query = frappe.get_all("DocField", {"fieldname": None}, run=0).get_sql()
self.assertIn("IS NULL", query)
self.assertNotIn("\\'", query)
self.assertNotIn("ifnull", query)
self.assertFalse(frappe.get_all("DocField", {"name": None}))
self.assertFalse(frappe.get_all("DocField", {"parent": None}))
self.assertNotIn("0", frappe.get_all("DocField", {"parent": None}, run=0))
self.assertNotIn("0", frappe.get_all("DocField", {"parent": None}, run=0).get_sql())
def test_ifnull_fallback_types(self):
query = frappe.get_all("DocField", {"fieldname": ("!=", None)}, run=0)
query = frappe.get_all("DocField", {"fieldname": ("!=", None)}, run=0).get_sql()
# Fallbacks should always be of correct type
self.assertIn("''", query)
self.assertNotIn("0", query)

View file

@ -285,10 +285,10 @@ class TestNestedSet(IntegrationTestCase):
inclusive_link = {"link_field": ("descendants of (inclusive)", record)}
# db_query
self.assertNotIn(record, frappe.get_all(TEST_DOCTYPE, exclusive_filter, run=0))
self.assertIn(record, frappe.get_all(TEST_DOCTYPE, inclusive_filter, run=0))
self.assertNotIn(record, frappe.get_all(linked_doctype, exclusive_link, run=0))
self.assertIn(record, frappe.get_all(linked_doctype, inclusive_link, run=0))
self.assertNotIn(record, frappe.get_all(TEST_DOCTYPE, exclusive_filter, run=0).get_sql())
self.assertIn(record, frappe.get_all(TEST_DOCTYPE, inclusive_filter, run=0).get_sql())
self.assertNotIn(record, frappe.get_all(linked_doctype, exclusive_link, run=0).get_sql())
self.assertIn(record, frappe.get_all(linked_doctype, inclusive_link, run=0).get_sql())
# QB
self.assertNotIn(record, str(frappe.qb.get_query(TEST_DOCTYPE, filters=exclusive_filter)))

View file

@ -179,7 +179,7 @@ class TestPerformance(IntegrationTestCase):
frappe.get_list("User")
def test_no_ifnull_checks(self):
query = frappe.get_all("DocType", {"autoname": ("is", "set")}, run=0).lower()
query = frappe.get_all("DocType", {"autoname": ("is", "set")}, run=0).get_sql().lower()
self.assertNotIn("coalesce", query)
self.assertNotIn("ifnull", query)

View file

@ -1902,6 +1902,30 @@ class TestQuery(IntegrationTestCase):
# If we get here without PermissionError, the test passes
self.assertIn(self.normalize_sql("GROUP BY `created_date`"), self.normalize_sql(sql))
def test_between_datetime_expansion(self):
"""Test that date strings are expanded to datetime ranges for Datetime fields with 'between' operator"""
# Test with creation field (standard datetime field)
query = frappe.qb.get_query(
"User",
filters={"creation": ["between", ["2025-12-01", "2025-12-01"]]},
)
sql = query.get_sql()
# Date strings should be expanded to datetime ranges
self.assertIn("2025-12-01 00:00:00", sql)
self.assertIn("2025-12-01 23:59:59", sql)
def test_timespan_datetime_expansion(self):
"""Test that timespan operator expands dates to datetime ranges for Datetime fields"""
query = frappe.qb.get_query(
"User",
filters={"creation": ["timespan", "last 7 days"]},
)
sql = query.get_sql()
# Timespan should expand dates to datetime ranges (start of first day, end of last day)
# Should have times like 00:00:00 and 23:59:59
self.assertIn("00:00:00", sql)
self.assertIn("23:59:59", sql)
# This function is used as a permission query condition hook
def test_permission_hook_condition(user):