feat(notifications): add preview

This commit is contained in:
David 2024-05-21 20:05:08 +02:00
parent 13ba502257
commit b2a3102345
No known key found for this signature in database
GPG key ID: AB15A6AF1101390D
4 changed files with 167 additions and 0 deletions

View file

@ -146,6 +146,7 @@ frappe.ui.form.on("Notification", {
},
};
});
frm.preview_fields = frm.doc.__onload.preview_fields;
},
refresh: function (frm) {
frappe.notification.setup_fieldname_select(frm);
@ -161,6 +162,17 @@ frappe.ui.form.on("Notification", {
});
frm.get_field("is_standard").toggle(frappe.boot.developer_mode);
frm.trigger("event");
if (frm.doc.document_type) {
frm.add_custom_button(__("Preview"), () => {
const args = {
doc: frm.doc,
doctype: frm.doc.document_type,
preview_fields: frm.preview_fields,
};
let dialog = new frappe.views.RenderPreviewer(args);
return dialog;
});
}
},
document_type: function (frm) {
frappe.notification.setup_fieldname_select(frm);

View file

@ -73,11 +73,65 @@ class Notification(Document):
"""load message"""
if self.is_standard:
self.message = self.get_template()
self.set_onload(
"preview_fields",
[
{"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"},
{"label": _("Subject"), "fieldtype": "Data", "method": "preview_subject"},
{"label": _("Message"), "fieldtype": "Code", "method": "preview_message"},
],
)
def autoname(self):
if not self.name:
self.name = self.subject
# START: PreviewRenderer API
@frappe.whitelist()
def preview_meets_condition(self, preview_document):
if not self.condition:
return _("Yes")
try:
doc = frappe.get_cached_doc(self.document_type, preview_document)
return _("Yes") if frappe.safe_eval(self.condition, eval_locals=get_context(doc)) else _("No")
except Exception as e:
frappe.local.message_log = []
return _("Failed to evaluate conditions: {}").format(e)
@frappe.whitelist()
def preview_message(self, preview_document):
try:
doc = frappe.get_cached_doc(self.document_type, preview_document)
context = get_context(doc)
context.update({"alert": self, "comments": None})
if doc.get("_comments"):
context["comments"] = json.loads(doc.get("_comments"))
msg = frappe.render_template(self.message, context)
if self.channel == "SMS":
return frappe.utils.strip_html_tags(msg)
return msg
except Exception as e:
return _("Failed to render message: {}").format(e)
@frappe.whitelist()
def preview_subject(self, preview_document):
try:
doc = frappe.get_cached_doc(self.document_type, preview_document)
context = get_context(doc)
context.update({"alert": self, "comments": None})
if doc.get("_comments"):
context["comments"] = json.loads(doc.get("_comments"))
if not self.subject:
return _("No subject")
if "{" in self.subject:
return frappe.render_template(self.subject, context)
return self.subject
except Exception as e:
return _("Failed to render subject: {}").format(e)
# END: PreviewRenderer API
def validate(self):
if self.channel in ("Email", "Slack", "System Notification"):
validate_template(self.subject)

View file

@ -11,6 +11,7 @@ import "./frappe/form/templates/timeline_message_box.html";
import "./frappe/form/templates/users_in_sidebar.html";
import "./frappe/views/formview.js";
import "./frappe/views/render_preview.js";
import "./frappe/form/form.js";
import "./frappe/meta_tag.js";
import "./frappe/doctype/";

View file

@ -0,0 +1,100 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
frappe.provide("frappe.views");
frappe.views.RenderPreviewer = class RenderPreviewer {
constructor(opts) {
$.extend(this, opts);
this.make();
}
make() {
let me = this;
me.set_fields();
let fields = me.header_fields;
fields.push(...me.body_fields);
me.dialog = new frappe.ui.Dialog({
title: __("Preview on") + " " + __(me.doctype),
no_submit_on_enter: true,
fields: fields,
minimizable: true,
size: "large",
});
me.prepare();
me.dialog.show();
}
set_fields() {
let me = this;
me.header_fields = [
{
label: __("Reference Doctype"),
fieldtype: "Link",
fieldname: "doctype",
reqd: 1,
read_only: 1,
hidden: 1,
},
{
label: __("Document"),
fieldtype: "Dynamic Link",
fieldname: "preview_document",
options: "doctype",
reqd: 1,
onchange: () => me.render_previews(),
},
];
me.body_fields = [{ fieldtype: "Section Break" }];
me.preview_fields.forEach((spec) => {
let field = {
label: spec.label,
fieldtype: spec.fieldtype,
fieldname: spec.method,
read_only: 1,
};
if (spec.method === "preview_meets_condition") {
me.header_fields.push({ fieldtype: "Column Break" });
me.header_fields.push(field);
} else {
me.body_fields.push(field);
}
});
}
prepare() {
let me = this;
me.dialog.set_values({
doctype: me.doctype,
});
}
async render_previews() {
let me = this;
let preview_document = me.dialog.get_value("preview_document");
if (preview_document) {
let promises = [];
me.preview_fields.forEach((spec) => {
let fieldname = spec.method;
promises.push(
frappe
.xcall("run_doc_method", {
dt: me.doc.doctype,
dn: me.doc.name,
method: spec.method,
arg: preview_document,
})
.then((message) => me.dialog.set_value(fieldname, message))
);
});
await Promise.all(promises);
} else {
me.preview_fields.forEach((spec) => {
let fieldname = spec.method;
me.dialog.set_value(fieldname, null);
});
}
}
};