transformForm = async ({
  form,
  table,
  req,
  row,
  res,
  getRowQuery,
  viewname,
  optionsQuery,
}) => {
  let pseudo_row = {};
  if (!row) {
    table.fields.forEach((f) => {
      pseudo_row[f.name] = undefined;
    });
  }
  await traverse(form.layout, {
    container(segment) {
      if (segment.click_action) {
        segment.url = `javascript:view_post(this, 'run_action', {click_action: '${segment.click_action}', ...get_form_record(this) })`;
      }
    },
    async action(segment) {
      if (segment.action_style === "on_page_load") {
        segment.type = "blank";
        segment.style = {};
        if (segment.minRole && segment.minRole != 100) {
          const minRole = +segment.minRole;
          const userRole = req?.user?.role_id || 100;
          if (minRole < userRole) return;
        }
        if (req.method === "POST") return;

        //run action
        try {
          const actionResult = await run_action_column({
            col: { ...segment },
            referrer: req?.get?.("Referrer"),
            req,
            res,
            table,
            row: row || pseudo_row,
          });

          if (actionResult)
            segment.contents = script(
              domReady(
                `common_done(${JSON.stringify(actionResult)}, "${viewname}")`
              )
            );
        } catch (e) {
          getState().log(
            5,
            `Error in Edit ${viewname} on page load action: ${e.message}`
          );
          e.message = `Error in evaluating Run on Page Load action in view ${viewname}: ${e.message}`;
          throw e;
        }
      }
      if (segment.action_name === "Delete") {
        if (form.values && form.values[table.pk_name]) {
          segment.action_url = `/delete/${table.name}/${form.values[table.pk_name]}`;
        } else {
          segment.type = "blank";
          segment.contents = "";
        }
      } else if (
        segment.action_name === "form_action" &&
        segment.configuration?.form_action === "Save" &&
        table.fields.some((f) => f.type === "File")
      ) {
        let url = action_url(
          viewname,
          table,
          segment.action_name,
          row,
          segment.rndid,
          "rndid",
          segment.confirm
        );
        if (url.javascript) {
          //redo to include dynamic row
          const confirmStr = segment.confirm
            ? `if(confirm('Are you sure?'))`
            : "";
          url.javascript = `${confirmStr}view_post(this, 'run_action', get_form_data(this, '${segment.rndid}') );`;
        }
        segment.action_link = action_link(url, req, segment);
      } else if (
        !["Sign up", ...edit_build_in_actions].includes(segment.action_name) &&
        !segment.action_name.startsWith("Login")
      ) {
        let url = action_url(
          viewname,
          table,
          segment.action_name,
          row,
          segment.rndid,
          "rndid",
          segment.confirm
        );
        if (url.javascript) {
          //redo to include dynamic row
          const confirmStr = segment.confirm
            ? `if(confirm('Are you sure?'))`
            : "";

          url.javascript = `${confirmStr}view_post(this, 'run_action', {rndid:'${segment.rndid}', ...get_form_record(this)});`;
        }
        segment.action_link = action_link(url, req, segment);
      }
    },
    join_field(segment) {
      const qs = objToQueryString(segment.configuration);
      segment.sourceURL = `/field/show-calculated/${table.name}/${segment.join_field}/${segment.fieldview}?${qs}`;
    },
    tabs(segment) {
      const to_delete = new Set();
      (segment.showif || []).forEach((sif, ix) => {
        if (sif) {
          const showit = eval_expression(
            sif,
            row || pseudo_row,
            req.user,
            "Tab show if formula"
          );
          if (!showit) to_delete.add(ix);
        }
      });

      segment.titles = segment.titles.filter((v, ix) => !to_delete.has(ix));
      segment.contents = segment.contents.filter((v, ix) => !to_delete.has(ix));

      (segment.titles || []).forEach((t, ix) => {
        if (typeof t === "string" && t.includes("{{")) {
          segment.titles[ix] = interpolate(t, row, req.user, "Tab titles");
        }
      });
    },
    view_link(segment) {
      segment.type = "blank";
      const view_select = parse_view_select(segment.view);
      if (!row && view_select.type !== "Independent") {
        segment.contents = "";
      } else {
        const prefix =
          req.generate_email && req.get_base_url ? req.get_base_url() : "";
        const { key } = view_linker(
          segment,
          table.fields,
          (s) => s,
          isWeb(req),
          req.user,
          prefix,
          req.query,
          req,
          viewname
        );
        segment.contents = key(row || {});
      }
    },
    async view(segment) {
      //console.log(segment);
      const view_select = parse_view_select(segment.view, segment.relation);
      //console.log({ view_select });

      const view = View.findOne({ name: view_select.viewname });
      if (!view)
        throw new InvalidConfiguration(
          `Cannot find embedded view: ${view_select.viewname}`
        );
      // check if the relation path matches a ChildList relations
      let childListRelPath = false;
      if (segment.relation && view.table_id) {
        const targetTbl = Table.findOne({ id: view.table_id });
        const relation = new Relation(
          segment.relation,
          targetTbl.name,
          displayType(await view.get_state_fields())
        );
        childListRelPath = relation.type === RelationType.CHILD_LIST;
      }
      // Edit-in-edit
      if (
        view.viewtemplate === "Edit" &&
        (view_select.type === "ChildList" || childListRelPath)
      ) {
        if (childListRelPath) updateViewSelect(view_select);
        const childTable = Table.findOne({ id: view.table_id });
        const childForm = await getForm(
          childTable,
          view.name,
          view.configuration.columns,
          view.configuration.layout,
          row?.id,
          req,
          !isWeb(req)
        );
        traverseSync(childForm.layout, {
          field(segment) {
            segment.field_name = `${view_select.field_name}.${segment.field_name}`;
          },
        });
        for (const field of childForm.fields) {
          if (field.name === childTable.pk_name) {
            field.class = field.class
              ? `${field.class} omit-repeater-clone`
              : "omit-repeater-clone";
          }
        }
        await childForm.fill_fkey_options(false, optionsQuery, req.user);

        const fr = new FieldRepeat({
          name: view_select.field_name,
          label: view_select.field_name,
          fields: childForm.fields,
          layout: childForm.layout,
          metadata: {
            table_id: childTable.id,
            view: segment.view,
            relation: view_select.field_name,
            relation_path: segment.relation,
            order_field: segment.order_field,
          },
        });
        if (row?.id) {
          const childRows = getRowQuery
            ? await getRowQuery(
                view.table_id,
                view_select,
                row.id,
                segment.order_field
              )
            : await childTable.getRows(
                {
                  [view_select.field_name]: row.id,
                },
                segment.order_field ? { orderBy: segment.order_field } : {}
              );
          fr.metadata.rows = childRows;
          if (!fr.fields.map((f) => f.name).includes(childTable.pk_name))
            fr.fields.push({
              name: childTable.pk_name,
              input_type: "hidden",
            });
        }
        form.fields.push(fr);
        segment.type = "field_repeat";
        segment.field_repeat = fr;
        return;
      } // end edit in edit

      let state = {};
      let urlFormula;
      let needFields = new Set();
      if (view_select.type === "RelationPath" && view.table_id) {
        const pathToUrlFormula = (relation) => {
          const st = pathToState(relation, (k) => `row.` + k);
          return Object.entries(st)
            .map(([k, v]) => {
              needFields.add(v.split(".")[1]);
              return `${k}='+${v}+'`;
            })
            .join("&");
        };

        const targetTbl = Table.findOne({ id: view.table_id });
        if (targetTbl) {
          const relation = new Relation(
            segment.relation,
            targetTbl.name,
            displayType(await view.get_state_fields())
          );
          const relFmlQS = pathToUrlFormula(relation);
          const type = relation.type;
          if (!row && type == RelationType.OWN) {
            segment.type = "blank";
            urlFormula = `add_extra_state('/view/${view.name}/?${relFmlQS}', ${JSON.stringify(segment.extra_state_fml)}, row)`;
            segment.contents = segment.contents = div({
              class: "d-inline",
              "data-sc-embed-viewname": view.name,
              "data-view-source-need-fields": [...needFields].join(","),
              "data-view-source": encodeURIComponent(urlFormula),
            });
            return;
          } else if (
            !row &&
            type !== RelationType.INDEPENDENT &&
            !relation.isFixedRelation()
          ) {
            urlFormula = `add_extra_state('/view/${view.name}/?${relFmlQS}', ${JSON.stringify(segment.extra_state_fml)}, row)`;
            segment.contents = segment.contents = div({
              class: "d-inline",
              "data-sc-embed-viewname": view.name,
              "data-view-source-need-fields": [...needFields].join(","),
              "data-view-source": encodeURIComponent(urlFormula),
            });
            return;
          }
          const userId = req?.user?.id;
          state = pathToState(
            relation,
            relation.isFixedRelation() ? () => userId : (k) => row[k]
          );

          urlFormula = `add_extra_state('/view/${view.name}?${relFmlQS}', ${JSON.stringify(segment.extra_state_fml)}, row)`;
        }
      } else {
        const isIndependent = view_select.type === "Independent";
        // legacy none check ?

        if (!view)
          throw new InvalidConfiguration(
            `Edit view incorrectly configured: cannot find embedded view ${view_select.viewname}`
          );
        switch (view_select.type) {
          case "Own":
            state = { id: row?.id };
            urlFormula = `add_extra_state('/view/${view.name}/?id='+row.id, ${JSON.stringify(segment.extra_state_fml)}, row)`;
            needFields.add("id");
            break;
          case "Independent":
            state = {};
            urlFormula = `add_extra_state('/view/${view.name}/?id='+row.id, ${JSON.stringify(segment.extra_state_fml)}, row)`;
            needFields.add("id");
            break;
          case "ChildList":
          case "OneToOneShow":
            state = { [view_select.field_name]: row?.id };
            urlFormula = `add_extra_state('/view/${view.name}/?${view_select.field_name}='+row.id, ${JSON.stringify(segment.extra_state_fml)}, row)`;
            needFields.add("id");
            break;
          case "ParentShow":
            state = { id: row?.[view_select.field_name] };
            urlFormula = `add_extra_state('/view/${view.name}/?id='+row.${view_select.field_name}, ${JSON.stringify(segment.extra_state_fml)}, row)`;
            needFields.add(view_select.field_name);
            break;
        }
        if (!row && !isIndependent) {
          segment.type = "blank";
          segment.contents = div({
            class: "d-inline",
            "data-sc-embed-viewname": view.name,
            "data-view-source-need-fields": [...needFields].join(","),
            "data-view-source": encodeURIComponent(urlFormula),
          });
          return;
        }
      }
      const extra_state = segment.extra_state_fml
        ? eval_expression(
            segment.extra_state_fml,
            {
              ...dollarizeObject(req.query),
              session_id: getSessionId(req),
              ...(row || pseudo_row),
            },
            req.user,
            `Extra state formula for embedding view ${view.name}`
          )
        : {};
      const qs = stateToQueryString({ ...state, ...extra_state }, true);
      segment.contents = div(
        {
          class: "d-inline",
          "data-sc-embed-viewname": view.name,
          "data-sc-view-source": `/view/${view.name}${qs}`,
          "data-view-source-current": `/view/${view.name}${qs}`,
          "data-view-source-need-fields": [...needFields].join(","),
          "data-view-source": encodeURIComponent(urlFormula),
        },
        await view.run(
          { ...state, ...extra_state },
          { req, res },
          view.isRemoteTable()
        )
      );
    },
  });
  translateLayout(form.layout, req.getLocale());

  if (req.headers?.saltcornmodalrequest) form.xhrSubmit = true;
  setDateLocales(form, req.getLocale());
}
@param {object} opts
@param {Form} opts.form
@param {Table} opts.table
@param {object} opts.req
@param {object} opts.row
@param {object} opts.res
@throws {InvalidConfiguration}
@returns {Promise<void>}