How to override a form controls file?

I added some customization on /frappe-bench/apps/frappe/frappe/public/js/frappe/form/controls/link.js, how to make these changes in my custom app?

1 Like

I got the console error:
Cannot use import statement outside a module!

Any help?

Are you customizing the frappe app itself?
Or are you looking to customize your custom app.

If the latter, please create your js file in your custom app’s public/js directory.
Then create the hook to include this js in your app.

Thank you for your reply,
Let me explain to you what I am trying to do in details:

I want to modify on this menu list:
image

Let’s say I want to put condition to control the visibility of one of the buttons.
I modified directly on this code on the get_menu_items function and it worked.
https://github.com/frappe/frappe/blob/develop/frappe/public/js/frappe/views/reports/query_report.js

Now, I want to make the change on my custom app, I did the following:

  1. Created views/reports directories in public one, then add new_frame.bundle.js file. (new_frame is my app name)

  2. Put and modified the targeted piece of code in new_frame.bundle.js as follows:

frappe.views.QueryReport.prototype.get_menu_items = function () {
  let items = [
    {
      label: __("Refresh"),
      action: () => this.refresh(),
      class: "visible-xs",
    },
    {
      label: __("Edit"),
      action: () => frappe.set_route("Form", "Report", this.report_name),
      condition: () => frappe.user.is_report_manager(),
      standard: true,
    },
    {
      label: __("Print"),
      action: () => {
        let dialog = frappe.ui.get_print_settings(
          false,
          (print_settings) => this.print_report(print_settings),
          this.report_doc.letter_head,
          this.get_visible_columns()
        );
        this.add_portrait_warning(dialog);
      },
      condition: () => frappe.model.can_print(this.report_doc.ref_doctype),
      standard: true,
    },
    {
      label: __("PDF"),
      action: () => {
        let dialog = frappe.ui.get_print_settings(
          false,
          (print_settings) => this.pdf_report(print_settings),
          this.report_doc.letter_head,
          this.get_visible_columns()
        );

        this.add_portrait_warning(dialog);
      },
      condition: () => frappe.model.can_print(this.report_doc.ref_doctype),
      standard: true,
    },
    {
      label: __("Export"),
      action: () => this.export_report(),
      condition: () => frappe.model.can_export(this.report_doc.ref_doctype),
      standard: true,
    },
    {
      label: __("Setup Auto Email"),
      action: () =>
        frappe.set_route("List", "Auto Email Report", {
          report: this.report_name,
        }),
      standard: true,
    },
    {
      label: __("User Permissions"),
      action: () =>
        frappe.set_route("List", "User Permission", {
          doctype: "Report",
          name: this.report_name,
        }),
      condition: () => frappe.model.can_set_user_permissions("Report"),
      standard: true,
    },
  ];

  if (frappe.user.has_role("Omar")) {
    items.push({
      label: __("Add Column, Ya Pro! ~ From App ~"),
      action: () => {
        let d = new frappe.ui.Dialog({
          title: __("Add Column"),
          fields: [
            {
              fieldtype: "Select",
              fieldname: "doctype",
              label: __("From Document Type"),
              options: this.linked_doctypes.map((df) => ({
                label: df.doctype,
                value: df.doctype,
              })),
              change: () => {
                let doctype = d.get_value("doctype");
                frappe.model.with_doctype(doctype, () => {
                  let options = frappe.meta
                    .get_docfields(doctype)
                    .filter(frappe.model.is_value_type)
                    .map((df) => ({
                      label: df.label,
                      value: df.fieldname,
                    }));

                  d.set_df_property(
                    "field",
                    "options",
                    options.sort(function (a, b) {
                      if (a.label < b.label) {
                        return -1;
                      }
                      if (a.label > b.label) {
                        return 1;
                      }
                      return 0;
                    })
                  );
                });
              },
            },
            {
              fieldtype: "Select",
              label: __("Field"),
              fieldname: "field",
              options: [],
            },
            {
              fieldtype: "Select",
              label: __("Insert After"),
              fieldname: "insert_after",
              options: this.columns.map((df) => df.label),
            },
          ],
          primary_action: (values) => {
            const custom_columns = [];
            let df = frappe.meta.get_docfield(values.doctype, values.field);
            const insert_after_index = this.columns.findIndex(
              (column) => column.label === values.insert_after
            );
            custom_columns.push({
              fieldname: df.fieldname,
              fieldtype: df.fieldtype,
              label: df.label,
              insert_after_index: insert_after_index,
              link_field: this.doctype_field_map[values.doctype],
              doctype: values.doctype,
              options: df.options,
              width: 100,
            });

            this.custom_columns = this.custom_columns.concat(custom_columns);
            frappe.call({
              method: "frappe.desk.query_report.get_data_for_custom_field",
              args: {
                field: values.field,
                doctype: values.doctype,
                names: Array.from(this.doctype_field_map[values.doctype].names),
              },
              callback: (r) => {
                const custom_data = r.message;
                const link_field =
                  this.doctype_field_map[values.doctype].fieldname;

                this.add_custom_column(
                  custom_columns,
                  custom_data,
                  link_field,
                  values.field,
                  insert_after_index
                );
                d.hide();
              },
            });
            this.set_menu_items();
          },
        });

        d.show();
      },
      standard: true,
    });
  }

  if (frappe.user.is_report_manager()) {
    items.push({
      label: __("Save"),
      action: () => {
        let d = new frappe.ui.Dialog({
          title: __("Save Report"),
          fields: [
            {
              fieldtype: "Data",
              fieldname: "report_name",
              label: __("Report Name"),
              default:
                this.report_doc.is_standard == "No" ? this.report_name : "",
              reqd: true,
            },
          ],
          primary_action: (values) => {
            frappe.call({
              method: "frappe.desk.query_report.save_report",
              args: {
                reference_report: this.report_name,
                report_name: values.report_name,
                columns: this.get_visible_columns(),
                filters: this.get_filter_values(),
              },
              callback: function (r) {
                this.show_save = false;
                d.hide();
                frappe.set_route("query-report", r.message);
              },
            });
          },
        });
        d.show();
      },
      standard: true,
    });
  }

  return items;
};
  1. Added the file to hooks.py as:
app_include_js = "/assets/newframe/views/reports/new_frame.bundle.js"

Is this correct?