menuForm = async (req) => {
  const views = await View.find({}, { orderBy: "name", nocase: true });
  const pages = await Page.find({}, { orderBy: "name", nocase: true });
  const pageGroups = await PageGroup.find(
    {},
    { orderBy: "name", nocase: true }
  );
  const roles = await User.get_roles();
  const tables = await Table.find_with_external({});
  const dynTableOptions = tables.map((t) => t.name);
  const dynOrderFieldOptions = {},
    dynSectionFieldOptions = {};
  for (const table of tables) {
    dynOrderFieldOptions[table.name] = [""];
    dynSectionFieldOptions[table.name] = [""];
    const fields = table.getFields();
    for (const field of fields) {
      dynOrderFieldOptions[table.name].push(field.name);
      if (
        field.type &&
        field.type.name === "String" &&
        field.attributes &&
        field.attributes.options
      )
        dynSectionFieldOptions[table.name].push(field.name);
    }
  }
  const stateActions = getState().actions;
  const actions = [
    ...Object.entries(stateActions)
      .filter(([k, v]) => !v.requireRow && !v.disableInBuilder)
      .map(([k, v]) => k),
  ];
  const triggers = Trigger.find({
    when_trigger: { or: ["API call", "Never"] },
  });
  triggers.forEach((tr) => {
    actions.push(tr.name);
  });

  return new Form({
    action: "/menu/",
    submitLabel: req.__("Save"),
    id: "menuForm",
    labelCols: 3,
    noSubmitButton: true,
    additionalButtons: [
      { label: req.__("Update"), id: "btnUpdate", class: "btn btn-primary" },
      { label: req.__("Add"), id: "btnAdd", class: "btn btn-primary" },
      {
        label: req.__("Recalculate dynamic"),
        id: "btnRecalc",
        class: "btn btn-primary",
      },
    ],
    fields: [
      {
        name: "type",
        label: req.__("Type"),
        input_type: "select",
        class: "menutype item-menu",
        required: true,
        options: [
          "View",
          "Page",
          "Page Group",
          "Link",
          "Header",
          "Dynamic",
          "Search",
          "Separator",
          "Action",
        ],
      },
      {
        name: "url",
        label: req.__("URL"),
        class: "item-menu validate-expression validate-expression-conditional",
        input_type: "text",
        showIf: { type: "Link" },
      },
      {
        name: "url_formula",
        label: req.__("URL is a formula?"),
        type: "Bool",
        class: "item-menu",
        required: false,
        showIf: { type: "Link" },
      },
      {
        name: "pagename",
        label: req.__("Page"),
        input_type: "select",
        class: "item-menu",
        options: pages.map((r) => r.name),
        showIf: { type: "Page" },
      },
      {
        name: "viewname",
        label: req.__("View"),
        type: "String",
        class: "item-menu",
        required: true,
        attributes: { options: views.map((r) => r.select_option) },
        showIf: { type: "View" },
      },
      {
        name: "page_group",
        label: req.__("Page group"),
        input_type: "select",
        class: "item-menu",
        options: pageGroups.map((r) => r.name),
        showIf: { type: "Page Group" },
      },
      {
        name: "action_name",
        label: req.__("Action"),
        type: "String",
        class: "item-menu",
        required: true,
        attributes: {
          options: actions,
        },
        showIf: { type: "Action" },
      },
      {
        name: "dyn_table",
        label: req.__("Table"),
        class: "item-menu",
        type: "String",
        attributes: {
          options: dynTableOptions,
        },
        required: true,
        showIf: { type: "Dynamic" },
      },
      {
        name: "dyn_order",
        label: req.__("Order field"),
        class: "item-menu",
        type: "String",
        attributes: {
          calcOptions: ["dyn_table", dynOrderFieldOptions],
        },
        showIf: { type: "Dynamic" },
      },
      {
        name: "dyn_section_field",
        label: req.__("Section field"),
        class: "item-menu",
        type: "String",
        attributes: {
          calcOptions: ["dyn_table", dynSectionFieldOptions],
        },
        sublabel: req.__(
          "Optional. String type with options, each of which will become a menu section"
        ),
        showIf: { type: "Dynamic" },
      },
      {
        name: "dyn_label_fml",
        label: req.__("Label formula"),
        class: "item-menu",
        type: "String",
        required: true,
        showIf: { type: "Dynamic" },
      },
      {
        name: "dyn_tooltip_fml",
        label: req.__("Tooltip formula"),
        class: "item-menu",
        type: "String",
        required: false,
        showIf: { type: "Dynamic" },
      },
      {
        name: "dyn_url_fml",
        label: req.__("URL formula"),
        class: "item-menu",
        type: "String",
        required: true,
        showIf: { type: "Dynamic" },
      },
      {
        name: "dyn_include_fml",
        label: req.__("Include formula"),
        sublabel: req.__(
          "If specified, only include in menu rows that evaluate to true"
        ),
        class: "item-menu",
        type: "String",
        required: true,
        showIf: { type: "Dynamic" },
      },
      {
        name: "text",
        label: req.__("Text label"),
        class: "item-menu",
        input_type: "text",
        required: true,
        showIf: {
          type: [
            "View",
            "Page",
            "Page Group",
            "Link",
            "Header",
            "Dynamic",
            "Search",
            "Action",
          ],
        },
      },
      {
        name: "icon_btn",
        label: req.__("Icon"),
        input_type: "custom_html",
        attributes: {
          html: `<button type="button" id="myEditor_icon" class="btn btn-outline-secondary"></button>`,
        },
        showIf: {
          type: ["View", "Page", "Page Group", "Link", "Header", "Action"],
        },
      },
      {
        name: "icon",
        class: "item-menu",
        input_type: "hidden",
        showIf: {
          type: ["View", "Page", "Page Group", "Link", "Header", "Action"],
        },
      },
      {
        name: "tooltip",
        label: req.__("Tooltip"),
        class: "item-menu",
        input_type: "text",
        required: false,
        showIf: {
          type: [
            "View",
            "Page",
            "Page Group",
            "Link",
            "Header",
            "Dynamic",
            "Search",
            "Action",
          ],
        },
      },
      {
        name: "min_role",
        label: req.__("Minimum role"),
        class: "item-menu",
        input_type: "select",
        options: roles.map((r) => ({ label: r.role, value: r.id })),
      },
      {
        name: "max_role",
        label: req.__("Maximum role"),
        class: "item-menu",
        input_type: "select",
        options: roles.map((r) => ({ label: r.role, value: r.id })),
      },
      {
        name: "disable_on_mobile",
        label: req.__("Disable on mobile"),
        type: "Bool",
        class: "item-menu",
        required: false,
        default: false,
      },
      {
        name: "mobile_item_html",
        label: req.__("Mobile HTML"),
        sublabel: req.__(
          "HTML for the item in the bottom navigation bar. Currently, only supported by the metronic theme."
        ),
        type: "String",
        class: "item-menu",
        input_type: "textarea",
        showIf: { disable_on_mobile: false, location: "Mobile Bottom" },
      },
      {
        name: "target_blank",
        label: req.__("Open in new tab"),
        type: "Bool",
        required: false,
        class: "item-menu",
        showIf: { type: ["View", "Page", "Page Group", "Link"] },
      },
      {
        name: "in_modal",
        label: req.__("Open in popup modal?"),
        type: "Bool",
        required: false,
        class: "item-menu",
        showIf: { type: ["View", "Page", "Page Group", "Link"] },
      },
      {
        name: "style",
        label: req.__("Style"),
        sublabel: req.__("Not all themes support menu buttons"),
        class: "item-menu",
        type: "String",
        required: true,
        showIf: {
          type: [
            "View",
            "Page",
            "Page Group",
            "Link",
            "Header",
            "Dynamic",
            "Action",
          ],
        },
        attributes: {
          options: [
            { name: "", label: req.__("Link") },
            { name: "btn btn-primary", label: req.__("Primary button") },
            { name: "btn btn-secondary", label: req.__("Secondary button") },
            { name: "btn btn-success", label: req.__("Success button") },
            { name: "btn btn-danger", label: req.__("Danger button") },
            {
              name: "btn btn-outline-primary",
              label: req.__("Primary outline button"),
            },
            {
              name: "btn btn-outline-secondary",
              label: req.__("Secondary outline button"),
            },
          ],
        },
      },
      {
        name: "location",
        label: req.__("Location"),
        showIf: {
          type: [
            "View",
            "Page",
            "Page Group",
            "Link",
            "Header",
            "Dynamic",
            "Search",
            "Separator",
            "Action",
          ],
        },
        sublabel: req.__("Not all themes support all locations"),
        class: "item-menu",
        type: "String",
        //fieldview: "radio_group",
        required: true,
        //default: "Standard",
        attributes: {
          inline: true,
          options: ["Standard", "Mobile Bottom", "Secondary Menu"],
        },
      },
    ],
  });
}
Menu Form
@param {object} req
@returns {Promise<Form>}