diff --git a/cypress/integration/form_builder.js b/cypress/integration/form_builder.js index b298abdbe7..bf7ab86008 100644 --- a/cypress/integration/form_builder.js +++ b/cypress/integration/form_builder.js @@ -9,38 +9,23 @@ context("Form Builder", () => { it("Open Form Builder for Web Form Doctype/Customize Form", () => { // doctype - cy.visit("/app/form-builder/Web Form"); + cy.visit("/app/doctype/Web Form"); + cy.findByRole("tab", { name: "Form" }).click(); cy.get(".form-builder-container").should("exist"); // customize form - cy.visit("/app/form-builder/Web Form/customize"); + cy.visit("/app/customize-form?doc_type=Web%20Form"); + cy.findByRole("tab", { name: "Form" }).click(); cy.get(".form-builder-container").should("exist"); }); - it("Change Doctype using page title dialog", () => { - cy.intercept("POST", "/api/method/frappe.desk.search.search_link").as("search_link"); - - cy.visit(`/app/form-builder/Web Form`); - cy.get(".form-builder-container").should("exist"); - - cy.get(".page-title").click(); - - cy.get(".frappe-control[data-fieldname='doctype'] input").click().as("input"); - cy.get("@input").type("{rightArrow}Web Form Field", { delay: 200 }); - cy.wait("@search_link"); - cy.get("@input").type("{enter}").blur(); - - cy.click_modal_primary_button("Edit"); - - cy.get(".page-title .title-text").should("have.text", "Web Form Field"); - }); - - it("Save without change, check form dirty and reset changes", () => { - cy.visit(`/app/form-builder/${doctype_name}`); + it("Save without change, check form dirty", () => { + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); // Save without change cy.click_doc_primary_button("Save"); - cy.get(".desk-alert.orange .alert-message").should("have.text", "No changes to save"); + cy.get(".desk-alert.orange .alert-message").should("have.text", "No changes in document"); // Check form dirty cy.get(".tab-content.active .section-columns-container:first .column:first .field:first") @@ -48,14 +33,11 @@ context("Form Builder", () => { .dblclick() .type("Dirty"); cy.get(".title-area .indicator-pill.orange").should("have.text", "Not Saved"); - - // Reset changes - cy.get(".page-actions .custom-actions .btn").contains("Reset Changes").click(); - cy.get(".title-area .indicator-pill.orange").should("not.exist"); }); it("Add empty section and save", () => { - cy.visit(`/app/form-builder/${doctype_name}`); + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); let first_section = ".tab-content.active .form-section-container:first"; @@ -71,7 +53,8 @@ context("Form Builder", () => { it("Add Table field and check if columns are rendered", () => { cy.intercept("POST", "/api/method/frappe.desk.search.search_link").as("search_link"); - cy.visit(`/app/form-builder/${doctype_name}`); + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); let first_field = ".tab-content.active .section-columns-container:first .column:first .field:first"; @@ -126,20 +109,23 @@ context("Form Builder", () => { }); it("Drag Field/Column/Section & Tab", () => { - cy.visit(`/app/form-builder/${doctype_name}`); + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); let first_column = ".tab-content.active .section-columns-container:first .column:first"; let first_field = first_column + " .field:first"; let label = "div[title='Double click to edit label'] span:first"; + cy.get(".tab-header .tabs .tab:first").click(); + // drag first tab to second position - cy.get(".tabs .tab:first").drag(".tabs .tab:nth-child(2)", { + cy.get(".tab-header .tabs .tab:first").drag(".tab-header .tabs .tab:nth-child(2)", { target: { x: 10, y: 10 }, force: true, }); - cy.get(".tabs .tab:first").find(label).should("have.text", "Tab 2"); + cy.get(".tab-header .tabs .tab:first").find(label).should("have.text", "Tab 2"); - cy.get(".tabs .tab:first").click(); + cy.get(".tab-header .tabs .tab:first").click(); cy.get(".sidebar-container .tab:first").click(); // drag check field to first column @@ -151,7 +137,7 @@ context("Form Builder", () => { cy.get(first_field) .find("div[title='Double click to edit label']") .dblclick() - .type("Test Check{enter}"); + .type("Test Check"); cy.get(first_field).find(label).should("have.text", "Test Check"); // drag the first field to second position @@ -184,13 +170,14 @@ context("Form Builder", () => { }); it("Add New Tab/Section/Column to Form", () => { - cy.visit(`/app/form-builder/${doctype_name}`); + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); let first_section = ".tab-content.active .form-section-container:first"; // add new tab cy.get(".tab-header").realHover().find(".tab-actions .new-tab-btn").click(); - cy.get(".tabs .tab").should("have.length", 3); + cy.get(".tab-header .tabs .tab").should("have.length", 3); // add new section cy.get(first_section).click(15, 10); @@ -218,11 +205,12 @@ context("Form Builder", () => { // remove tab cy.get(".tab-header").realHover().find(".tab-actions .remove-tab-btn").click(); - cy.get(".tabs .tab").should("have.length", 2); + cy.get(".tab-header .tabs .tab").should("have.length", 2); }); it("Update Title field Label to New Title through Customize Form", () => { - cy.visit(`/app/form-builder/${doctype_name}`); + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); let first_field = ".tab-content.active .section-columns-container:first .column:first .field:first"; @@ -239,7 +227,8 @@ context("Form Builder", () => { }); it("Validate Duplicate Name & reqd + hidden without default logic", () => { - cy.visit(`/app/form-builder/${doctype_name}`); + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); let first_field = ".tab-content.active .section-columns-container:first .column:first .field:first"; @@ -275,10 +264,11 @@ context("Form Builder", () => { }); it("Undo/Redo", () => { - cy.visit(`/app/form-builder/${doctype_name}`); + cy.visit(`/app/doctype/${doctype_name}`); + cy.findByRole("tab", { name: "Form" }).click(); // click on second tab - cy.get(".tabs .tab:last").click(); + cy.get(".tab-header .tabs .tab:last").click(); let first_column = ".tab-content.active .section-columns-container:first .column:first"; let first_field = first_column + " .field:first"; diff --git a/cypress/integration/grid_configuration.js b/cypress/integration/grid_configuration.js index 9112d7023e..3d49ed1503 100644 --- a/cypress/integration/grid_configuration.js +++ b/cypress/integration/grid_configuration.js @@ -4,6 +4,8 @@ context("Grid Configuration", () => { cy.visit("/app/doctype/User"); }); it("Set user wise grid settings", () => { + cy.findByRole("tab", { name: "Form" }).click(); + cy.get('.form-section[data-fieldname="fields_section"]').click(); cy.wait(100); cy.get('.frappe-control[data-fieldname="fields"]').as("table"); cy.get("@table").find(".icon-sm").click(); diff --git a/cypress/integration/sidebar.js b/cypress/integration/sidebar.js index 0f97cdc7fe..91c38ef6ce 100644 --- a/cypress/integration/sidebar.js +++ b/cypress/integration/sidebar.js @@ -27,60 +27,70 @@ context("Sidebar", () => { }); it("Verify attachment visibility config", () => { - verify_attachment_visibility("doctype/Blog Post", true); + cy.call("frappe.tests.ui_test_helpers.create_todo", { + description: "Sidebar Attachment ToDo", + }).then((todo) => { + verify_attachment_visibility(`todo/${todo.message.name}`, true); + }); verify_attachment_visibility("blog-post/test-blog-attachment-post", false); }); it('Test for checking "Assigned To" counter value, adding filter and adding & removing an assignment', () => { - cy.visit("/app/doctype"); - cy.click_sidebar_button("Assigned To"); + cy.call("frappe.tests.ui_test_helpers.create_todo", { + description: "Sidebar Attachment ToDo", + }).then((todo) => { + let todo_name = todo.message.name; + cy.visit("/app/todo"); + cy.click_sidebar_button("Assigned To"); - //To check if no filter is available in "Assigned To" dropdown - cy.get(".empty-state").should("contain", "No filters found"); + //To check if no filter is available in "Assigned To" dropdown + cy.get(".empty-state").should("contain", "No filters found"); - //Assigning a doctype to a user - cy.visit("/app/doctype/ToDo"); - cy.get(".form-assignments > .flex > .text-muted").click(); - cy.get_field("assign_to_me", "Check").click(); - cy.get(".modal-footer > .standard-actions > .btn-primary").click(); - cy.visit("/app/doctype"); - cy.click_sidebar_button("Assigned To"); + //Assigning a doctype to a user + cy.visit(`/app/todo/${todo_name}`); + cy.get(".form-assignments > .flex > .text-muted").click(); + cy.get_field("assign_to_me", "Check").click(); + cy.get(".modal-footer > .standard-actions > .btn-primary").click(); + cy.visit("/app/todo"); + cy.click_sidebar_button("Assigned To"); - //To check if filter is added in "Assigned To" dropdown after assignment - cy.get(".group-by-field.show > .dropdown-menu > .group-by-item > .dropdown-item").should( - "contain", - "1" - ); + //To check if filter is added in "Assigned To" dropdown after assignment + cy.get( + ".group-by-field.show > .dropdown-menu > .group-by-item > .dropdown-item" + ).should("contain", "1"); - //To check if there is no filter added to the listview - cy.get(".filter-button").should("contain", "Filter"); + //To check if there is no filter added to the listview + cy.get(".filter-button").should("contain", "Filter"); - //To add a filter to display data into the listview - cy.get(".group-by-field.show > .dropdown-menu > .group-by-item > .dropdown-item").click(); + //To add a filter to display data into the listview + cy.get( + ".group-by-field.show > .dropdown-menu > .group-by-item > .dropdown-item" + ).click(); - //To check if filter is applied - cy.click_filter_button().should("contain", "1 filter"); - cy.get(".fieldname-select-area > .awesomplete > .form-control").should( - "have.value", - "Assigned To" - ); - cy.get(".condition").should("have.value", "like"); - cy.get(".filter-field > .form-group > .input-with-feedback").should( - "have.value", - `%${cy.config("testUser")}%` - ); - cy.click_filter_button(); + //To check if filter is applied + cy.click_filter_button().should("contain", "1 filter"); + cy.get(".fieldname-select-area > .awesomplete > .form-control").should( + "have.value", + "Assigned To" + ); + cy.get(".condition").should("have.value", "like"); + cy.get(".filter-field > .form-group > .input-with-feedback").should( + "have.value", + `%${cy.config("testUser")}%` + ); + cy.click_filter_button(); - //To remove the applied filter - cy.clear_filters(); + //To remove the applied filter + cy.clear_filters(); - //To remove the assignment - cy.visit("/app/doctype/ToDo"); - cy.get(".assignments > .avatar-group > .avatar > .avatar-frame").click(); - cy.get(".remove-btn").click({ force: true }); - cy.hide_dialog(); - cy.visit("/app/doctype"); - cy.click_sidebar_button("Assigned To"); - cy.get(".empty-state").should("contain", "No filters found"); + //To remove the assignment + cy.visit(`/app/todo/${todo_name}`); + cy.get(".assignments > .avatar-group > .avatar > .avatar-frame").click(); + cy.get(".remove-btn").click({ force: true }); + cy.hide_dialog(); + cy.visit("/app/todo"); + cy.click_sidebar_button("Assigned To"); + cy.get(".empty-state").should("contain", "No filters found"); + }); }); }); diff --git a/frappe/core/doctype/doctype/doctype.js b/frappe/core/doctype/doctype/doctype.js index bb2af5cec0..650729aef6 100644 --- a/frappe/core/doctype/doctype/doctype.js +++ b/frappe/core/doctype/doctype/doctype.js @@ -2,6 +2,26 @@ // MIT License. See license.txt frappe.ui.form.on("DocType", { + before_save: function (frm) { + let form_builder = frappe.form_builder; + if (form_builder?.store) { + let fields = form_builder.store.update_fields(); + + // if fields is a string, it means there is an error + if (typeof fields === "string") { + frappe.throw(fields); + } + } + }, + after_save: function (frm) { + if ( + frappe.form_builder && + frappe.form_builder.doctype === frm.doc.name && + frappe.form_builder.store + ) { + frappe.form_builder.store.fetch(); + } + }, refresh: function (frm) { frm.set_query("role", "permissions", function (doc) { if (doc.custom && frappe.session.user != "Administrator") { @@ -21,8 +41,6 @@ frappe.ui.form.on("DocType", { frm.toggle_enable("beta", 0); } - render_form_builder_message(frm); - if (!frm.is_new() && !frm.doc.istable) { if (frm.doc.issingle) { frm.add_custom_button(__("Go to {0}", [__(frm.doc.name)]), () => { @@ -72,6 +90,8 @@ frappe.ui.form.on("DocType", { frm.cscript.autoname(frm); frm.cscript.set_naming_rule_description(frm); frm.trigger("setup_default_views"); + + render_form_builder(frm); }, istable: (frm) => { @@ -142,4 +162,30 @@ function render_form_builder_message(frm) { } } +function render_form_builder(frm) { + if (frappe.form_builder && frappe.form_builder.doctype === frm.doc.name) { + frappe.form_builder.setup_page_actions(); + frappe.form_builder.store.fetch(); + return; + } + + if (frappe.form_builder) { + frappe.form_builder.wrapper = $(frm.fields_dict["form_builder"].wrapper); + frappe.form_builder.frm = frm; + frappe.form_builder.doctype = frm.doc.name; + frappe.form_builder.customize = false; + frappe.form_builder.init(true); + frappe.form_builder.store.fetch(); + } else { + frappe.require("form_builder.bundle.js").then(() => { + frappe.form_builder = new frappe.ui.FormBuilder({ + wrapper: $(frm.fields_dict["form_builder"].wrapper), + frm: frm, + doctype: frm.doc.name, + customize: false, + }); + }); + } +} + extend_cscript(cur_frm.cscript, new frappe.model.DocTypeController({ frm: cur_frm })); diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json index 5209a408eb..d42fa62802 100644 --- a/frappe/core/doctype/doctype/doctype.json +++ b/frappe/core/doctype/doctype/doctype.json @@ -25,9 +25,6 @@ "beta", "is_virtual", "queue_in_background", - "fields_section_break", - "try_form_builder_html", - "fields", "sb1", "naming_rule", "autoname", @@ -35,6 +32,32 @@ "column_break_15", "description", "documentation", + "sb2", + "permissions", + "restrict_to_domain", + "read_only", + "in_create", + "actions_section", + "actions", + "links_section", + "links", + "document_states_section", + "states", + "web_view", + "has_web_view", + "allow_guest_to_view", + "index_web_pages_for_search", + "route", + "is_published_field", + "website_search_field", + "advanced", + "engine", + "migration_hash", + "form_builder_tab", + "form_builder", + "fields_section", + "fields", + "settings_tab", "form_settings_section", "image_field", "timeline_field", @@ -68,28 +91,7 @@ "column_break_51", "email_append_to", "sender_field", - "subject_field", - "sb2", - "permissions", - "restrict_to_domain", - "read_only", - "in_create", - "actions_section", - "actions", - "links_section", - "links", - "document_states_section", - "states", - "web_view", - "has_web_view", - "allow_guest_to_view", - "index_web_pages_for_search", - "route", - "is_published_field", - "website_search_field", - "advanced", - "engine", - "migration_hash" + "subject_field" ], "fields": [ { @@ -195,12 +197,6 @@ "fieldtype": "Check", "label": "Beta" }, - { - "fieldname": "fields_section_break", - "fieldtype": "Section Break", - "label": "Fields", - "oldfieldtype": "Section Break" - }, { "fieldname": "fields", "fieldtype": "Table", @@ -633,9 +629,25 @@ "label": "Is Calendar and Gantt" }, { - "fieldname": "try_form_builder_html", + "fieldname": "settings_tab", + "fieldtype": "Tab Break", + "label": "Settings" + }, + { + "fieldname": "form_builder_tab", + "fieldtype": "Tab Break", + "label": "Form" + }, + { + "fieldname": "form_builder", "fieldtype": "HTML", - "label": "Try Form Builder HTML" + "label": "Form Builder" + }, + { + "collapsible": 1, + "fieldname": "fields_section", + "fieldtype": "Section Break", + "label": "Fields" } ], "icon": "fa fa-bolt", @@ -718,7 +730,7 @@ "link_fieldname": "reference_doctype" } ], - "modified": "2023-05-15 14:07:51.526257", + "modified": "2023-07-12 13:56:26.185637", "modified_by": "Administrator", "module": "Core", "name": "DocType", @@ -755,4 +767,4 @@ "states": [], "track_changes": 1, "translated_doctype": 1 -} +} \ No newline at end of file diff --git a/frappe/core/doctype/doctype/doctype_list.js b/frappe/core/doctype/doctype/doctype_list.js deleted file mode 100644 index f4811fa01d..0000000000 --- a/frappe/core/doctype/doctype/doctype_list.js +++ /dev/null @@ -1,28 +0,0 @@ -frappe.listview_settings["DocType"] = { - onload: function (me) { - me.page.btn_primary.addClass("hidden"); - this.setup_select_primary_button(me); - }, - - setup_select_primary_button: function (me) { - let actions = [ - { - label: __("Add DocType (Form Builder)"), - description: __("Use the form builder to create a new DocType"), - action: () => frappe.set_route("form-builder", "new-doctype"), - }, - { - label: __("Add DocType"), - description: __("Create a new DocType"), - action: () => frappe.new_doc("DocType"), - }, - ]; - - frappe.utils.add_select_group_button( - me.page.btn_primary.parent(), - actions, - "btn-primary", - "add" - ); - }, -}; diff --git a/frappe/custom/doctype/customize_form/customize_form.js b/frappe/custom/doctype/customize_form/customize_form.js index bd711c169d..c2e2e83d7f 100644 --- a/frappe/custom/doctype/customize_form/customize_form.js +++ b/frappe/custom/doctype/customize_form/customize_form.js @@ -100,8 +100,6 @@ frappe.ui.form.on("Customize Form", { frm.page.set_title(__("Customize Form - {0}", [frm.doc.doc_type])); frappe.customize_form.set_primary_action(frm); - render_form_builder_message(frm); - frm.add_custom_button( __("Go to {0} List", [__(frm.doc.doc_type)]), function () { @@ -149,6 +147,8 @@ frappe.ui.form.on("Customize Form", { ["queue_in_background"], frappe.get_meta(frm.doc.doc_type).is_submittable || 0 ); + + render_form_builder(frm); }); } @@ -334,37 +334,6 @@ frappe.ui.form.on("DocType State", { }, }); -frappe.customize_form.validate_fieldnames = async function (frm) { - for (let i = 0; i < frm.doc.fields.length; i++) { - let field = frm.doc.fields[i]; - - let fieldname = field.label && frappe.model.scrub(field.label).toLowerCase(); - if ( - field.label && - !field.fieldname && - in_list(frappe.model.restricted_fields, fieldname) - ) { - let message = __( - "For field {0} in row {1}, fieldname {2} is restricted it will be renamed as {2}1. Do you want to continue?", - [field.label, field.idx, fieldname] - ); - await pause_to_confirm(message); - } - } - - function pause_to_confirm(message) { - return new Promise((resolve) => { - frappe.confirm( - message, - () => resolve(), - () => { - frm.page.btn_primary.prop("disabled", false); - } - ); - }); - } -}; - frappe.customize_form.save_customization = function (frm) { if (frm.doc.doc_type) { return frm.call({ @@ -383,9 +352,22 @@ frappe.customize_form.save_customization = function (frm) { } }; +frappe.customize_form.update_fields_from_form_builder = function (frm) { + let form_builder = frappe.form_builder; + if (form_builder?.store) { + let fields = form_builder.store.update_fields(); + + // if fields is a string, it means there is an error + if (typeof fields === "string") { + frappe.throw(fields); + } + frm.refresh_fields(); + } +}; + frappe.customize_form.set_primary_action = function (frm) { - frm.page.set_primary_action(__("Update"), async () => { - await this.validate_fieldnames(frm); + frm.page.set_primary_action(__("Update"), () => { + this.update_fields_from_form_builder(frm); this.save_customization(frm); }); }; @@ -433,30 +415,29 @@ frappe.customize_form.clear_locals_and_refresh = function (frm) { frm.refresh(); }; -function render_form_builder_message(frm) { - $(frm.fields_dict["try_form_builder_html"].wrapper).empty(); - if (!frm.is_new() && frm.fields_dict["try_form_builder_html"]) { - let title = __("Use Form Builder to visually customize your form layout"); - let msg = __( - "You can drag and drop fields to create your form layout, add tabs, sections and columns to organize your form and update field properties all from one screen." - ); +function render_form_builder(frm) { + if (frappe.form_builder && frappe.form_builder.doctype === frm.doc.doc_type) { + frappe.form_builder.setup_page_actions(); + frappe.form_builder.store.fetch(); + return; + } - let message = ` -
- `; - - $(frm.fields_dict["try_form_builder_html"].wrapper).html(message); + if (frappe.form_builder) { + frappe.form_builder.wrapper = $(frm.fields_dict["form_builder"].wrapper); + frappe.form_builder.frm = frm; + frappe.form_builder.doctype = frm.doc.doc_type; + frappe.form_builder.customize = true; + frappe.form_builder.init(true); + frappe.form_builder.store.fetch(); + } else { + frappe.require("form_builder.bundle.js").then(() => { + frappe.form_builder = new frappe.ui.FormBuilder({ + wrapper: $(frm.fields_dict["form_builder"].wrapper), + frm: frm, + doctype: frm.doc.doc_type, + customize: true, + }); + }); } } diff --git a/frappe/custom/doctype/customize_form/customize_form.json b/frappe/custom/doctype/customize_form/customize_form.json index e0d822eb61..d3c8c661e7 100644 --- a/frappe/custom/doctype/customize_form/customize_form.json +++ b/frappe/custom/doctype/customize_form/customize_form.json @@ -21,12 +21,20 @@ "allow_auto_repeat", "allow_import", "queue_in_background", - "fields_section_break", - "try_form_builder_html", - "fields", "naming_section", "naming_rule", "autoname", + "document_actions_section", + "actions", + "document_links_section", + "links", + "document_states_section", + "states", + "form_tab", + "form_builder", + "fields_section_break", + "fields", + "settings_tab", "form_settings_section", "image_field", "max_attachments", @@ -48,12 +56,6 @@ "email_append_to", "sender_field", "subject_field", - "document_actions_section", - "actions", - "document_links_section", - "links", - "document_states_section", - "states", "section_break_8", "sort_field", "column_break_10", @@ -174,8 +176,8 @@ "options": "ASC\nDESC" }, { + "collapsible": 1, "depends_on": "doc_type", - "description": "Customize Label, Print Hide, Default etc.", "fieldname": "fields_section_break", "fieldtype": "Section Break", "label": "Fields" @@ -369,9 +371,19 @@ "label": "Is Calendar and Gantt" }, { - "fieldname": "try_form_builder_html", + "fieldname": "settings_tab", + "fieldtype": "Tab Break", + "label": "Settings" + }, + { + "fieldname": "form_builder", "fieldtype": "HTML", - "label": "Try Form Builder HTML" + "label": "Form Builder" + }, + { + "fieldname": "form_tab", + "fieldtype": "Tab Break", + "label": "Form" } ], "hide_toolbar": 1, @@ -380,7 +392,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-05-15 16:03:19.872532", + "modified": "2023-07-16 13:25:46.201184", "modified_by": "Administrator", "module": "Custom", "name": "Customize Form", diff --git a/frappe/desk/page/form_builder/__init__.py b/frappe/desk/page/form_builder/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frappe/desk/page/form_builder/form_builder.js b/frappe/desk/page/form_builder/form_builder.js deleted file mode 100644 index a7a25b5c6c..0000000000 --- a/frappe/desk/page/form_builder/form_builder.js +++ /dev/null @@ -1,211 +0,0 @@ -frappe.pages["form-builder"].on_page_load = function (wrapper) { - frappe.ui.make_app_page({ - parent: wrapper, - title: __("Form Builder"), - single_column: true, - }); - - // hot reload in development - if (frappe.boot.developer_mode) { - frappe.hot_update = frappe.hot_update || []; - frappe.hot_update.push(() => load_form_builder(wrapper)); - } -}; - -frappe.pages["form-builder"].on_page_show = function (wrapper) { - load_form_builder(wrapper); -}; - -function load_form_builder(wrapper) { - let route = frappe.get_route(); - route = route.filter((a) => a); - - if (route.length > 1 && route[1] === "new-doctype") { - frappe.pages["form-builder"].new_doctype(route[2]); - } else if (route.length > 1) { - let doctype = route[1]; - let is_customize_form = route[2] === "customize"; - - if (frappe.form_builder?.doctype) { - frappe.form_builder.doctype = frappe.form_builder.store.doctype = doctype; - frappe.form_builder.customize = frappe.form_builder.store.is_customize_form = - is_customize_form; - frappe.form_builder.init(true); - frappe.form_builder.store.fetch(); - return; - } - - let $parent = $(wrapper).find(".layout-main-section"); - $parent.empty(); - - frappe.require("form_builder.bundle.js").then(() => { - frappe.form_builder = new frappe.ui.FormBuilder({ - wrapper: $parent, - page: wrapper.page, - doctype: doctype, - customize: is_customize_form, - }); - }); - } else { - frappe.pages["form-builder"].select_doctype(); - } -} - -frappe.pages["form-builder"].select_doctype = function () { - let d = new frappe.ui.Dialog({ - title: __("Select DocType"), - fields: [ - { - label: __("Select DocType"), - fieldname: "doctype", - fieldtype: "Link", - options: "DocType", - only_select: 1, - }, - { - label: __("Customize"), - fieldname: "customize", - fieldtype: "Check", - }, - ], - primary_action_label: __("Edit"), - primary_action({ doctype, customize }) { - if (customize) { - frappe.model.with_doctype(doctype).then(() => { - let meta = frappe.get_meta(doctype); - if (in_list(frappe.model.core_doctypes_list, this.doctype)) - frappe.throw(__("Core DocTypes cannot be customized.")); - - if (meta.issingle) frappe.throw(__("Single DocTypes cannot be customized.")); - - if (meta.custom) - frappe.throw( - __( - "Only standard DocTypes are allowed to be customized from Customize Form." - ) - ); - frappe.set_route("form-builder", doctype, "customize"); - }); - } else { - frappe.set_route("form-builder", doctype); - } - }, - secondary_action_label: __("Create New DocType"), - secondary_action() { - let doctype = d.get_value("doctype") || ""; - d.hide(); - frappe.set_route("form-builder", "new-doctype", doctype); - }, - }); - - d.show(); -}; - -frappe.pages["form-builder"].new_doctype = function (doctype) { - let non_developer = frappe.session.user !== "Administrator" || !frappe.boot.developer_mode; - let new_d = new frappe.ui.Dialog({ - title: __("Create New DocType"), - fields: [ - { - label: __("DocType Name"), - fieldname: "doctype_name", - fieldtype: "Data", - default: doctype, - reqd: 1, - }, - { fieldtype: "Column Break" }, - { - label: __("Module"), - fieldname: "module", - fieldtype: "Link", - options: "Module Def", - reqd: 1, - }, - { fieldtype: "Section Break" }, - { - label: __("Is Submittable"), - fieldname: "is_submittable", - fieldtype: "Check", - description: __( - "Once submitted, submittable documents cannot be changed. They can only be Cancelled and Amended." - ), - depends_on: "eval:!doc.istable && !doc.issingle", - }, - { - label: __("Is Child Table"), - fieldname: "istable", - fieldtype: "Check", - description: __("Child Tables are shown as a Grid in other DocTypes"), - depends_on: "eval:!doc.is_submittable && !doc.issingle", - }, - { - label: __("Editable Grid"), - fieldname: "editable_grid", - fieldtype: "Check", - depends_on: "istable", - default: 1, - }, - { - label: __("Is Single"), - fieldname: "issingle", - fieldtype: "Check", - description: __( - "Single Types have only one record no tables associated. Values are stored in tabSingles" - ), - depends_on: "eval:!doc.istable && !doc.is_submittable", - }, - { - label: __("Custom?"), - fieldname: "custom", - fieldtype: "Check", - default: non_developer, - read_only: non_developer, - }, - ], - primary_action_label: __("Create & Continue"), - primary_action(values) { - if (!values.istable) values.editable_grid = 0; - frappe.db - .insert({ - doctype: "DocType", - name: values.doctype_name, - module: values.module, - istable: values.istable, - editable_grid: values.editable_grid, - issingle: values.issingle, - custom: values.custom, - is_submittable: values.is_submittable, - permissions: [ - { - create: 1, - delete: 1, - email: 1, - export: 1, - print: 1, - read: 1, - report: 1, - role: "System Manager", - share: 1, - write: 1, - }, - ], - fields: [ - { - label: "Title", - fieldname: "title", - fieldtype: "Data", - }, - ], - }) - .then((doc) => { - frappe.set_route("form-builder", doc.name); - }); - }, - secondary_action_label: __("Back"), - secondary_action() { - new_d.hide(); - window.history.back(); - }, - }); - new_d.show(); -}; diff --git a/frappe/desk/page/form_builder/form_builder.json b/frappe/desk/page/form_builder/form_builder.json deleted file mode 100644 index afeacecd90..0000000000 --- a/frappe/desk/page/form_builder/form_builder.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "content": null, - "creation": "2022-10-10 22:42:53.597423", - "docstatus": 0, - "doctype": "Page", - "idx": 0, - "modified": "2022-10-10 22:42:53.597423", - "modified_by": "Administrator", - "module": "Desk", - "name": "form-builder", - "owner": "Administrator", - "page_name": "form-builder", - "roles": [], - "script": null, - "standard": "Yes", - "style": null, - "system_page": 0, - "title": "Form Builder" -} \ No newline at end of file diff --git a/frappe/public/js/form_builder/FormBuilder.vue b/frappe/public/js/form_builder/FormBuilder.vue index c1ab90c4a4..4dd04f5b70 100644 --- a/frappe/public/js/form_builder/FormBuilder.vue +++ b/frappe/public/js/form_builder/FormBuilder.vue @@ -3,7 +3,7 @@ import Sidebar from "./components/Sidebar.vue" import Tabs from "./components/Tabs.vue"; import { computed, onMounted, watch, ref } from "vue"; import { useStore } from "./store"; -import { onClickOutside, useMagicKeys, whenever } from "@vueuse/core"; +import { onClickOutside } from "@vueuse/core"; let store = useStore(); @@ -14,19 +14,6 @@ let should_render = computed(() => { let container = ref(null); onClickOutside(container, () => store.form.selected_field = null); -// cmd/ctrl + s to save the form -const { meta_s, ctrl_s } = useMagicKeys(); -whenever(() => meta_s.value || ctrl_s.value, () => { - if (store.dirty) { - store.save_changes(); - } -}); - -function setup_change_doctype_dialog() { - store.page.$title_area.on("click", () => { - frappe.pages["form-builder"].select_doctype(); - }); -} watch( () => store.form.layout, @@ -34,10 +21,7 @@ watch( { deep: true } ); -onMounted(() => { - store.fetch(); - setup_change_doctype_dialog(); -}); +onMounted(() => store.fetch()); @@ -62,9 +46,8 @@ onMounted(() => {