run = async (
  table_id,
  viewname,
  { columns, layout, page_title, page_title_formula },
  state,
  extra,
  { showQuery }
) => {
  //console.log(columns);
  //console.log(layout);
  if (!columns || !layout) return "View not yet built";
  const tbl = Table.findOne(table_id);
  const fields = await tbl.getFields();
  if (tbl.name === "users") {
    fields.push(
      new Field({
        name: "verification_token",
        label: "Verification Token",
        type: "String",
      }),
      new Field({
        name: "reset_password_token",
        label: "Reset Password Token",
        type: "String",
      })
    );
  }
  const { rows, message } = await showQuery(state);
  if (message) return extra.req.__(message);
  if (rows.length > 1)
    rows.sort((a, b) => {
      let diff = 0;
      Object.keys(state).forEach((key) => {
        if (a[key] && b[key]) {
          if (typeof a[key] === "string" && typeof b[key] === "string") {
            diff += a[key].length - b[key].length;
          }
        }
      });
      return diff;
    });

  if (rows.length == 0) return extra.req.__("No row selected");
  if (tbl.name === "users") {
    const base = get_base_url(extra.req);
    fields.push(
      new Field({
        name: "verification_url",
        label: "Verification URL",
        type: "String",
      }),
      new Field({
        name: "reset_password_url",
        label: "Reset Password URL",
        type: "String",
      })
    );
    for (const row of rows) {
      row.verification_url = `${base}auth/verify?token=${
        row.verification_token
      }&email=${encodeURIComponent(row.email)}`;
      row.reset_password_url = `${base}auth/reset?token=${
        row.reset_password_token
      }&email=${encodeURIComponent(row.email)}`;
    }
  }
  await set_load_actions_join_fieldviews({
    table: tbl,
    layout,
    fields,
    req: extra.req,
    res: extra.res,
    row: rows[0],
    isPreview: extra.isPreview,
  });

  const rendered = (
    await renderRows(
      tbl,
      viewname,
      { columns, layout },
      extra,
      [rows[0]],
      state
    )
  )[0];

  //legacy
  let page_title_preamble = "";
  if (page_title) {
    let the_title = page_title;
    if (page_title_formula) {
      const f = get_expression_function(page_title, fields);
      the_title = f(rows[0]);
    }
    page_title_preamble = `<!--SCPT:${text_attr(the_title)}-->`;
  }

  if (!extra.req.generate_email) return page_title_preamble + rendered;
  else {
    return rendered;
  }
}
@param {string} table_id
@param {string} viewname
@param {object} opts
@param {object[]} opts.columns
@param {object} opts.layout
@param {string} [opts.page_title]
@param {boolean} opts.page_title_formula
@param {object} state
@param {object} extra
@returns {Promise<string>}