refactor: make RoleEditor child table fields configurable (#38394)

This commit is contained in:
Raffael Meyer 2026-04-03 21:46:24 +02:00 committed by GitHub
parent 707f685154
commit efe39fdce3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,13 +1,38 @@
frappe.RoleEditor = class {
constructor(wrapper, frm, disable) {
/**
* Create a role editor for a form child table.
*
* @param {HTMLElement|JQuery} wrapper Container for the MultiCheck control.
* @param {frappe.ui.form.Form} frm Form whose role rows are edited.
* @param {boolean|number|Object} [disable=false] Disable role selection inputs, or pass role row configuration as the third argument.
* @param {Object} [options] Role row configuration overrides.
* @param {string} [options.table_fieldname="roles"] Child table field containing role rows.
* @param {string} [options.role_fieldname="role"] Field in each child row that stores the role value.
* @param {string} [options.child_doctype] Child DocType used when adding role rows. Defaults to the table field's configured child DocType or "Has Role".
*/
constructor(wrapper, frm, disable = false, options = {}) {
if (disable && typeof disable === "object") {
options = disable;
disable = false;
}
const { table_fieldname = "roles", role_fieldname = "role", child_doctype } = options;
const configured_child_doctype = frappe.meta.get_docfield(
frm.doctype,
table_fieldname
)?.options;
this.frm = frm;
this.wrapper = wrapper;
this.disable = disable;
let user_roles = this.frm.doc.roles ? this.frm.doc.roles.map((a) => a.role) : [];
this.disable = Boolean(disable);
this.table_fieldname = table_fieldname;
this.role_fieldname = role_fieldname;
this.child_doctype = child_doctype || configured_child_doctype || "Has Role";
let user_roles = this.get_selected_roles();
this.multicheck = frappe.ui.form.make_control({
parent: wrapper,
df: {
fieldname: "roles",
fieldname: this.table_fieldname,
fieldtype: "MultiCheck",
select_all: true,
columns: "15rem",
@ -130,25 +155,41 @@ frappe.RoleEditor = class {
}
reset() {
let user_roles = (this.frm.doc.roles || []).map((a) => a.role);
let user_roles = this.get_selected_roles();
this.multicheck.selected_options = user_roles;
this.multicheck.refresh_input();
}
set_roles_in_table() {
let roles = this.frm.doc.roles || [];
let roles = this.get_role_rows();
let checked_options = this.multicheck.get_checked_options();
roles.map((role_doc) => {
if (!checked_options.includes(role_doc.role)) {
roles.forEach((role_doc) => {
if (!checked_options.includes(this.get_role_value(role_doc))) {
frappe.model.clear_doc(role_doc.doctype, role_doc.name);
}
});
checked_options.map((role) => {
if (!roles.find((d) => d.role === role)) {
let role_doc = frappe.model.add_child(this.frm.doc, "Has Role", "roles");
role_doc.role = role;
checked_options.forEach((role) => {
if (!roles.find((d) => this.get_role_value(d) === role)) {
let role_doc = frappe.model.add_child(
this.frm.doc,
this.child_doctype,
this.table_fieldname
);
this.set_role_value(role_doc, role);
}
});
}
get_role_rows() {
return this.frm.doc[this.table_fieldname] || [];
}
get_selected_roles() {
return this.get_role_rows().map((row) => this.get_role_value(row));
}
get_role_value(row) {
return row[this.role_fieldname];
}
set_role_value(row, role) {
row[this.role_fieldname] = role;
}
get_roles() {
return {
checked_roles: this.multicheck.get_checked_options(),