From b41d517249fdc9050e2e0f5669a2cf558f1b8054 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Sun, 21 Jun 2026 09:58:43 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20'Block=20DocTypes'=20editor=20button=20?= =?UTF-8?q?=E2=80=94=20block=20any=20doctype,=20incl.=20not=20on=20/desk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- jey_layout/api.py | 11 +++++- jey_layout/public/css/jey_layout.css | 28 ++++++++++++++ jey_layout/public/js/jey_layout.js | 55 ++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/jey_layout/api.py b/jey_layout/api.py index 781aff1..45591dc 100644 --- a/jey_layout/api.py +++ b/jey_layout/api.py @@ -219,7 +219,16 @@ def _validate_config(cfg: dict) -> dict: if order: entry["order"] = order 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): diff --git a/jey_layout/public/css/jey_layout.css b/jey_layout/public/css/jey_layout.css index 6733f00..c38e3db 100644 --- a/jey_layout/public/css/jey_layout.css +++ b/jey_layout/public/css/jey_layout.css @@ -204,3 +204,31 @@ body.jey-edit .links-widget-box { outline: 1px dashed var(--border-color); 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); +} diff --git a/jey_layout/public/js/jey_layout.js b/jey_layout/public/js/jey_layout.js index 3d144bb..d63ab24 100644 --- a/jey_layout/public/js/jey_layout.js +++ b/jey_layout/public/js/jey_layout.js @@ -80,6 +80,7 @@ const $fab = $(`
+
@@ -91,10 +92,64 @@ `).appendTo("body"); $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="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(`
${__("No blocked doctypes yet.")}
`); + return; + } + list.forEach((dt, i) => { + const $row = $( + `
πŸ”’ ` + + `
` + ); + $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() { const $fab = $("#jey-fab"); $fab.toggleClass("on", editing);