config_fields_form = async ({
  field_names,
  req,
  action,
  ...formArgs
}) => {
  const values = {};
  const state = getState();
  const fields = [];
  const tenant = db.getTenantSchema();
  const roleAttribs = {
    options: (await User.get_roles()).map((r) => ({
      label: r.role,
      name: `${r.id}`,
    })),
  };
  const getTenants = async () => {
    const tens = await db.select("_sc_tenants");
    return { options: tens.map((t) => t.subdomain) };
  };
  for (const name0 of field_names) {
    if (typeof name0 === "object" && name0.section_header) {
      fields.push({
        input_type: "section_header",
        label: req.__(name0.section_header),
        sublabel: name0.sublabel ? req.__(name0.sublabel) : undefined,
      });
      continue;
    }
    let name, showIf;
    if (typeof name0 === "object" && name0.name) {
      name = name0.name;
      showIf = name0.showIf;
    } else {
      name = name0;
    }
    values[name] = state.getConfig(name);
    // console.log(`config field name: %s`,name);
    if (configTypes[name].root_only && tenant !== db.connectObj.default_schema)
      continue;
    const isView = (configTypes[name].type || "").startsWith("View ");
    const isRole = configTypes[name].type === "Role";
    const isTenant = configTypes[name].type === "Tenant";
    const isPage = configTypes[name].type === "Page";
    const label = configTypes[name].label || name;
    const sublabel = configTypes[name].sublabel || configTypes[name].blurb;

    if (configTypes[name].type === "Repeat") {
      const repFields = configTypes[name].fields;
      const filledFields = [];
      for (const rfield of repFields) {
        const fillField = new Field(rfield);
        await fillField.fill_fkey_options();
        filledFields.push(fillField);
      }
      fields.push(
        new FieldRepeat({
          name,
          label,
          fields: filledFields,
          showIf,
        })
      );

      continue;
    }

    if (!state.isFixedConfig(name))
      fields.push({
        name,
        ...configTypes[name],
        label: label ? req.__(label) : undefined,
        sublabel:
          (sublabel ? req.__(sublabel) : "") +
          (isView
            ? ". " +
              a(
                {
                  "data-dyn-href": `\`/viewedit/config/\${${name}}\``,
                  "data-show-if": `showIfFormulaInputs($('select[name=${name}]'), '${name}')`,
                  target: "_blank",
                },
                req.__("Configure")
              )
            : ""),
        type:
          isView || isRole || isTenant || isPage
            ? "String"
            : configTypes[name].input_type
              ? undefined
              : configTypes[name].type,
        input_type: configTypes[name].input_type,
        showIf,
        help: configTypes[name].helpTopic
          ? { topic: configTypes[name].helpTopic }
          : undefined,
        attributes: isView
          ? await viewAttributes(name)
          : isRole
            ? roleAttribs
            : isTenant
              ? await getTenants()
              : isPage
                ? {
                    options: (await Page.find()).map((p) => ({
                      label: p.name,
                      name: p.name,
                    })),
                  }
                : configTypes[name].attributes,
      });
  }
  const form = new Form({
    fields,
    values,
    action,
    noSubmitButton: true,
    onChange: `saveAndContinue(this)`,
    ...formArgs,
  });
  await form.fill_fkey_options();
  return form;
}
Config fields form
@param {object} opts
@param {string[]} opts.field_names
@param {object} opts.req
@param {*} opts.formArgs
@returns {Promise<Form>}