feat: 'Block DocTypes' editor button — block any doctype, incl. not on /desk
Adds an edit-mode menu action + dialog to manage a global blocked_doctypes list (Link picker + remove), persisted in the working config and validated server-side. Lets you block doctypes that have no link on the desk. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
17893b06ae
commit
b41d517249
|
|
@ -219,7 +219,16 @@ def _validate_config(cfg: dict) -> dict:
|
||||||
if order:
|
if order:
|
||||||
entry["order"] = order
|
entry["order"] = order
|
||||||
out_ws[ws_name] = entry
|
out_ws[ws_name] = entry
|
||||||
return {"version": 1, "workspaces": out_ws}
|
|
||||||
|
out = {"version": 1, "workspaces": out_ws}
|
||||||
|
# Global block list: doctypes blocked anywhere (incl. ones not on /desk).
|
||||||
|
blocked_doctypes = []
|
||||||
|
for dt in cfg.get("blocked_doctypes") or []:
|
||||||
|
if isinstance(dt, str) and dt and dt not in blocked_doctypes:
|
||||||
|
blocked_doctypes.append(dt)
|
||||||
|
if blocked_doctypes:
|
||||||
|
out["blocked_doctypes"] = blocked_doctypes
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def _write(path: str, cfg: dict):
|
def _write(path: str, cfg: dict):
|
||||||
|
|
|
||||||
|
|
@ -204,3 +204,31 @@ body.jey-edit .links-widget-box {
|
||||||
outline: 1px dashed var(--border-color);
|
outline: 1px dashed var(--border-color);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Block DocTypes dialog */
|
||||||
|
.jey-blocked-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.jey-blocked-row .dt {
|
||||||
|
flex: 1;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.jey-blocked-x {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--red-500, #e24c4c);
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.jey-blocked-x:hover {
|
||||||
|
background: var(--red-100, #fce4e4);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@
|
||||||
const $fab = $(`
|
const $fab = $(`
|
||||||
<div id="jey-fab">
|
<div id="jey-fab">
|
||||||
<div class="jey-fab-menu">
|
<div class="jey-fab-menu">
|
||||||
|
<button data-act="block">🔒 ${__("Block DocTypes")}</button>
|
||||||
<button data-act="export">${__("Export to jey_theme")}</button>
|
<button data-act="export">${__("Export to jey_theme")}</button>
|
||||||
<button data-act="reset">${__("Reset to default")}</button>
|
<button data-act="reset">${__("Reset to default")}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -91,10 +92,64 @@
|
||||||
`).appendTo("body");
|
`).appendTo("body");
|
||||||
|
|
||||||
$fab.find(".jey-fab-btn").on("click", toggle_edit);
|
$fab.find(".jey-fab-btn").on("click", toggle_edit);
|
||||||
|
$fab.find('[data-act="block"]').on("click", open_block_doctypes_dialog);
|
||||||
$fab.find('[data-act="export"]').on("click", do_export);
|
$fab.find('[data-act="export"]').on("click", do_export);
|
||||||
$fab.find('[data-act="reset"]').on("click", do_reset);
|
$fab.find('[data-act="reset"]').on("click", do_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global block list — block any doctype, including ones not present on /desk.
|
||||||
|
function open_block_doctypes_dialog() {
|
||||||
|
let list = (config.blocked_doctypes || []).slice();
|
||||||
|
const d = new frappe.ui.Dialog({
|
||||||
|
title: __("Block DocTypes (anywhere, incl. not on the desk)"),
|
||||||
|
fields: [
|
||||||
|
{ fieldname: "add", label: __("Add a DocType to block"), fieldtype: "Link", options: "DocType" },
|
||||||
|
{ fieldname: "list_html", fieldtype: "HTML" },
|
||||||
|
],
|
||||||
|
primary_action_label: __("Save"),
|
||||||
|
primary_action: async () => {
|
||||||
|
if (list.length) config.blocked_doctypes = list;
|
||||||
|
else delete config.blocked_doctypes;
|
||||||
|
await save_now();
|
||||||
|
d.hide();
|
||||||
|
frappe.show_alert(
|
||||||
|
{ message: __("Saved — “✓ Done editing” to apply the block"), indicator: "green" },
|
||||||
|
5
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const render = () => {
|
||||||
|
const $w = d.fields_dict.list_html.$wrapper;
|
||||||
|
$w.empty();
|
||||||
|
if (!list.length) {
|
||||||
|
$w.html(`<div class="text-muted" style="padding:6px 0">${__("No blocked doctypes yet.")}</div>`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
list.forEach((dt, i) => {
|
||||||
|
const $row = $(
|
||||||
|
`<div class="jey-blocked-row">🔒 <span class="dt"></span>` +
|
||||||
|
`<button type="button" class="jey-blocked-x" title="${__("Remove")}">✕</button></div>`
|
||||||
|
);
|
||||||
|
$row.find(".dt").text(dt);
|
||||||
|
$row.find(".jey-blocked-x").on("click", () => {
|
||||||
|
list.splice(i, 1);
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
$w.append($row);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
d.fields_dict.add.df.onchange = () => {
|
||||||
|
const v = d.get_value("add");
|
||||||
|
if (v) {
|
||||||
|
if (!list.includes(v)) list.push(v);
|
||||||
|
d.set_value("add", "");
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
render();
|
||||||
|
d.show();
|
||||||
|
}
|
||||||
|
|
||||||
function update_fab() {
|
function update_fab() {
|
||||||
const $fab = $("#jey-fab");
|
const $fab = $("#jey-fab");
|
||||||
$fab.toggleClass("on", editing);
|
$fab.toggleClass("on", editing);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue