Merge branch 'develop' into feature/show-full-number-option

This commit is contained in:
UmakanthKaspa 2025-05-22 11:43:18 +05:30 committed by GitHub
commit 868a019e4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 73 additions and 32 deletions

View file

@ -666,7 +666,7 @@ def is_whitelisted(method):
is_guest = session["user"] == "Guest"
if method not in whitelisted or (is_guest and method not in guest_methods):
summary = _("You are not permitted to access this resource.")
summary = _("You are not permitted to access this resource. Login to access")
detail = _("Function {0} is not whitelisted.").format(bold(f"{method.__module__}.{method.__name__}"))
msg = f"<details><summary>{summary}</summary>{detail}</details>"
throw(msg, PermissionError, title=_("Method Not Allowed"))

View file

@ -33,6 +33,7 @@
"editable_grid",
"quick_entry",
"grid_page_length",
"rows_threshold_for_grid_search",
"cb01",
"track_changes",
"track_seen",
@ -697,6 +698,14 @@
"fieldname": "protect_attached_files",
"fieldtype": "Check",
"label": "Protect Attached Files"
},
{
"default": "0",
"depends_on": "istable",
"fieldname": "rows_threshold_for_grid_search",
"fieldtype": "Int",
"label": "Rows Threshold for Grid Search",
"non_negative": 1
}
],
"grid_page_length": 50,
@ -775,7 +784,7 @@
"link_fieldname": "document_type"
}
],
"modified": "2025-03-27 18:16:53.286909",
"modified": "2025-05-21 21:58:59.947374",
"modified_by": "Administrator",
"module": "Core",
"name": "DocType",

View file

@ -161,6 +161,7 @@ class DocType(Document):
restrict_to_domain: DF.Link | None
route: DF.Data | None
row_format: DF.Literal["Dynamic", "Compressed"]
rows_threshold_for_grid_search: DF.Int
search_fields: DF.Data | None
sender_field: DF.Data | None
sender_name_field: DF.Data | None

View file

@ -71,30 +71,37 @@ def has_permission(doc, user):
def get_unseen_notes():
from frappe.query_builder.terms import ParameterizedValueWrapper, SubQuery
def _get_unseen_notes():
note = frappe.qb.DocType("Note")
nsb = frappe.qb.DocType("Note Seen By").as_("nsb")
return (
frappe.qb.from_(note)
.select(note.name, note.title, note.content, note.notify_on_every_login)
.where(
(note.notify_on_login == 1)
& (note.expire_notification_on > frappe.utils.now())
& (
ParameterizedValueWrapper(frappe.session.user).notin(
SubQuery(frappe.qb.from_(nsb).select(nsb.user).where(nsb.parent == note.name))
)
)
)
).run(as_dict=1)
return (
frappe.cache.get_value(
f"{UNSEEN_NOTES_KEY}{frappe.session.user}",
generator=_get_unseen_notes,
)
or []
)
@frappe.whitelist()
def reset_notes():
frappe.cache.set_value(f"{UNSEEN_NOTES_KEY}{frappe.session.user}", [])
return frappe.cache.get_value(f"{UNSEEN_NOTES_KEY}{frappe.session.user}")
def _get_unseen_notes():
from frappe.query_builder.terms import ParameterizedValueWrapper, SubQuery
note = frappe.qb.DocType("Note")
nsb = frappe.qb.DocType("Note Seen By").as_("nsb")
results = (
frappe.qb.from_(note)
.select(note.name, note.title, note.content, note.notify_on_every_login)
.where(
(note.notify_on_login == 1)
& (note.expire_notification_on > frappe.utils.now())
& (
ParameterizedValueWrapper(frappe.session.user).notin(
SubQuery(frappe.qb.from_(nsb).select(nsb.user).where(nsb.parent == note.name))
)
)
)
).run(as_dict=1)
frappe.cache.set_value(f"{UNSEEN_NOTES_KEY}{frappe.session.user}", results)

View file

@ -32,7 +32,9 @@
"dynamic_filters_section",
"dynamic_filters_json",
"section_break_16",
"color"
"color",
"column_break_xtre",
"background_color"
],
"fields": [
{
@ -209,6 +211,15 @@
"label": "Currency",
"options": "Currency"
},
{
"fieldname": "column_break_xtre",
"fieldtype": "Column Break"
},
{
"fieldname": "background_color",
"fieldtype": "Color",
"label": "Background Color"
},
{
"default": "0",
"description": "Check to display the full numeric value (e.g., 1,234,567 instead of 1.2M).",

View file

@ -23,6 +23,7 @@ class NumberCard(Document):
from frappe.types import DF
aggregate_function_based_on: DF.Literal[None]
background_color: DF.Color | None
color: DF.Color | None
currency: DF.Link | None
document_type: DF.Link | None

View file

@ -88,6 +88,7 @@ on_session_creation = [
"frappe.core.doctype.user.user.notify_admin_access_to_system_manager",
]
on_login = "frappe.desk.doctype.note.note._get_unseen_notes"
on_logout = "frappe.core.doctype.session_default_settings.session_default_settings.clear_session_defaults"
# PDF

View file

@ -469,11 +469,12 @@ frappe.Application = class Application {
if (frappe.boot.notes.length) {
frappe.boot.notes.forEach(function (note) {
if (!note.seen || note.notify_on_every_login) {
var d = frappe.msgprint({ message: note.content, title: note.title });
var d = new frappe.ui.Dialog({ content: note.content, title: note.title });
d.keep_open = true;
d.custom_onhide = function () {
d.msg_area = $('<div class="msgprint">').appendTo(d.body);
d.msg_area.append(note.content);
d.onhide = function () {
note.seen = true;
// Mark note as read if the Notify On Every Login flag is not set
if (!note.notify_on_every_login) {
frappe.call({
@ -482,11 +483,13 @@ frappe.Application = class Application {
note: note.name,
},
});
} else {
frappe.call({
method: "frappe.desk.doctype.note.note.reset_notes",
});
}
// next note
me.show_notes();
};
d.show();
}
});
}

View file

@ -852,8 +852,13 @@ export default class GridRow {
show_search_row() {
// show or remove search columns based on grid rows
let show_length =
this.grid?.meta?.rows_threshold_for_grid_search > 0
? this.grid.meta.rows_threshold_for_grid_search
: 20;
this.show_search =
this.show_search && (this.grid?.data?.length >= 20 || this.grid.filter_applied);
this.show_search &&
(this.grid?.data?.length >= show_length || this.grid.filter_applied);
!this.show_search && this.wrapper.remove();
return this.show_search;
}

View file

@ -157,6 +157,8 @@ export default class NumberCardWidget extends Widget {
async render_card() {
this.prepare_actions();
this.set_title();
this.card_doc?.background_color &&
this.widget.css("background-color", this.card_doc.background_color);
this.set_loading_state();
if (!this.card_doc.type) {

View file

@ -1,6 +1,6 @@
import frappe
from frappe.boot import get_user_pages_or_reports
from frappe.desk.doctype.note.note import get_unseen_notes, mark_as_seen
from frappe.desk.doctype.note.note import _get_unseen_notes, get_unseen_notes, mark_as_seen
from frappe.tests import IntegrationTestCase
@ -20,6 +20,7 @@ class TestBootData(IntegrationTestCase):
note.insert()
frappe.set_user("test@example.com")
_get_unseen_notes()
unseen_notes = [d.title for d in get_unseen_notes()]
self.assertListEqual(unseen_notes, ["Test Note"])