From d0d7ef8ae612ac4186d285ffeb9c0c2bc674d2d7 Mon Sep 17 00:00:00 2001 From: UmakanthKaspa Date: Fri, 13 Feb 2026 21:17:18 +0530 Subject: [PATCH] feat: add dynamic filters to Web Form list view --- .../js/frappe/web_form/web_form_list.js | 34 +++++++ .../js/frappe/web_form/webform_script.js | 1 + frappe/website/doctype/web_form/web_form.js | 89 +++++++++++++++++++ frappe/website/doctype/web_form/web_form.json | 14 ++- frappe/website/doctype/web_form/web_form.py | 1 + 5 files changed, 138 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index ae49106693..92514498e2 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -116,6 +116,40 @@ export default class WebFormList { this.filters = Object.assign(this.filters, JSON.parse(filter)); } + if (this.dynamic_filters_json) { + let dynamic_filters = JSON.parse(this.dynamic_filters_json); + if (dynamic_filters.length) { + dynamic_filters.forEach((f) => { + let expression = f[3]; + try { + f[3] = eval(f[3]); + } catch (e) { + frappe.throw( + __("Invalid expression set in filter {0} ({1}): {2}", [ + f[1], + f[0], + expression, + ]) + ); + } + if (f[3] == null) { + frappe.throw( + __("Invalid expression set in filter {0} ({1}): {2}", [ + f[1], + f[0], + expression, + ]) + ); + } + }); + let df_obj = {}; + dynamic_filters.forEach((f) => { + df_obj[f[1]] = [f[2], f[3]]; + }); + this.filters = Object.assign(this.filters, df_obj); + } + } + let args = { method: "frappe.www.list.get_list_data", args: { diff --git a/frappe/public/js/frappe/web_form/webform_script.js b/frappe/public/js/frappe/web_form/webform_script.js index 4c745a3909..09b71870bb 100644 --- a/frappe/public/js/frappe/web_form/webform_script.js +++ b/frappe/public/js/frappe/web_form/webform_script.js @@ -28,6 +28,7 @@ frappe.ready(function () { web_form_name: web_form_doc.name, list_columns: web_form_doc.list_columns, condition_json: web_form_doc.condition_json, + dynamic_filters_json: web_form_doc.dynamic_filters_json, settings: { allow_delete: web_form_doc.allow_delete, }, diff --git a/frappe/website/doctype/web_form/web_form.js b/frappe/website/doctype/web_form/web_form.js index 6c31cfe3fc..978a9cae9a 100644 --- a/frappe/website/doctype/web_form/web_form.js +++ b/frappe/website/doctype/web_form/web_form.js @@ -46,6 +46,7 @@ frappe.ui.form.on("Web Form", { frm.trigger("add_get_fields_button"); frm.trigger("add_publish_button"); frm.trigger("render_condition_table"); + frm.trigger("render_dynamic_filters_table"); }, login_required: function (frm) { @@ -203,9 +204,15 @@ frappe.ui.form.on("Web Form", { }, before_save: function (frm) { + let dynamic_filters = JSON.parse(frm.doc.dynamic_filters_json || "null"); let static_filters = JSON.parse(frm.doc.condition_json || "[]"); + static_filters = frappe.dashboard_utils.remove_common_static_filter_values( + static_filters, + dynamic_filters + ); frm.set_value("condition_json", JSON.stringify(static_filters)); frm.trigger("render_condition_table"); + frm.trigger("render_dynamic_filters_table"); }, render_condition_table: function (frm) { @@ -308,6 +315,88 @@ frappe.ui.form.on("Web Form", { dialog.set_values(filters); }); }, + render_dynamic_filters_table(frm) { + let wrapper = $(frm.get_field("dynamic_filters_json").wrapper).empty(); + + frm.dynamic_filter_table = $(` + + + + + + + + +
${__("Filter")}${__("Condition")}${__("Value")}
`).appendTo(wrapper); + + frm.dynamic_filters = + frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2 + ? JSON.parse(frm.doc.dynamic_filters_json) + : null; + + frm.trigger("set_dynamic_filters_in_table"); + + let filters = JSON.parse(frm.doc.condition_json || "[]"); + + let fields = frappe.dashboard_utils.get_fields_for_dynamic_filter_dialog( + true, + filters, + frm.dynamic_filters + ); + + frm.dynamic_filter_table.on("click", () => { + if (!frm.has_perm("write")) { + return; + } + + if (!frappe.boot.developer_mode && frm.doc.is_standard) { + frappe.throw(__("Cannot edit filters for standard Web Forms")); + } + let dialog = new frappe.ui.Dialog({ + title: __("Set Dynamic Filters"), + fields: fields, + primary_action: () => { + let values = dialog.get_values(); + dialog.hide(); + let dynamic_filters = []; + for (let key of Object.keys(values)) { + let [doctype, fieldname] = key.split(":"); + dynamic_filters.push([doctype, fieldname, "=", values[key]]); + } + frm.set_value("dynamic_filters_json", JSON.stringify(dynamic_filters)); + frm.trigger("set_dynamic_filters_in_table"); + }, + primary_action_label: __("Set"), + }); + + dialog.show(); + dialog.set_values(frm.dynamic_filters); + }); + }, + set_dynamic_filters_in_table: function (frm) { + frm.dynamic_filters = + frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2 + ? JSON.parse(frm.doc.dynamic_filters_json) + : null; + + if (!frm.dynamic_filters) { + const filter_row = $(` + ${__("Click to Set Dynamic Filters")}`); + frm.dynamic_filter_table.find("tbody").html(filter_row); + } else { + let filter_rows = ""; + frm.dynamic_filters.forEach((filter) => { + filter_rows += ` + ${filter[1]} + ${filter[2] || ""} + ${filter[3]} + `; + }); + frm.dynamic_filter_table.find("tbody").html(filter_rows); + } + }, }); frappe.ui.form.on("Web Form List Column", { diff --git a/frappe/website/doctype/web_form/web_form.json b/frappe/website/doctype/web_form/web_form.json index 6b03a6b988..c2e291bdfc 100644 --- a/frappe/website/doctype/web_form/web_form.json +++ b/frappe/website/doctype/web_form/web_form.json @@ -39,6 +39,8 @@ "condition_section", "condition_description", "condition_json", + "dynamic_filters_section", + "dynamic_filters_json", "section_break_3", "list_setting_message", "show_list", @@ -424,12 +426,22 @@ { "fieldname": "column_break_hhec", "fieldtype": "Column Break" + }, + { + "fieldname": "dynamic_filters_json", + "fieldtype": "JSON", + "label": "Dynamic Filters JSON" + }, + { + "fieldname": "dynamic_filters_section", + "fieldtype": "Section Break", + "label": "Dynamic Filters" } ], "icon": "icon-edit", "is_published_field": "published", "links": [], - "modified": "2025-12-12 16:29:35.806107", + "modified": "2026-02-13 19:59:19.807594", "modified_by": "Administrator", "module": "Website", "name": "Web Form", diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py index bd12631577..38a0ea1d2f 100644 --- a/frappe/website/doctype/web_form/web_form.py +++ b/frappe/website/doctype/web_form/web_form.py @@ -45,6 +45,7 @@ class WebForm(WebsiteGenerator): condition_json: DF.JSON | None custom_css: DF.Code | None doc_type: DF.Link + dynamic_filters_json: DF.JSON | None hide_footer: DF.Check hide_navbar: DF.Check introduction_text: DF.TextEditor | None