previewCSV = async ({ newPath, table, req, res, full }) => {
  let parse_res;
  try {
    parse_res = await table.import_csv_file(newPath, {
      recalc_stored: true,
      no_table_write: true,
    });
  } catch (e) {
    parse_res = { error: e.message };
  }
  if (parse_res.error) {
    if (parse_res.error) req.flash("error", parse_res.error);
    await fs.unlink(newPath);
    res.redirect(`/table/${table.id}`);
  } else {
    const rows = parse_res.rows || [];
    res.sendWrap(req.__(`Import table %s`, table.name), {
      above: [
        {
          type: "breadcrumbs",
          crumbs: [
            { text: req.__("Tables"), href: "/table" },
            { href: `/table/${table.id}`, text: table.name },
            {
              text: req.__("Import CSV"),
            },
          ],
        },
        {
          type: "card",
          title: req.__(`Import CSV`),
          contents: div(
            {
              "data-csv-filename": path.basename(newPath),
            },
            p(parse_res.success),
            post_btn(
              `/files/delete/${path.basename(newPath)}?redirect=/table/${
                table.id
              }}`,
              "Cancel",
              req.csrfToken(),
              {
                btnClass: "btn-danger mb-2",
                formClass: "d-inline me-2",
                icon: "fa fa-times",
              }
            ),
            form(
              {
                action: `/table/finish_upload_to_table/${table.name}/${path.basename(
                  newPath
                )}`,
                method: "post",
                class: "d-inline",
              },
              input({ type: "hidden", name: "_csrf", value: req.csrfToken() }),
              button(
                { type: "submit", class: "btn btn-primary mb-2" },
                i({ class: "fa fa-check" }),
                "Proceed"
              ),
              br(),
              i({ class: "muted" }, "Method"),
              select(
                {
                  name: "import_method",
                  class: "form-select from-control mb-2",
                },
                option("Auto"),
                option({ value: "copy" }, "COPY (fast but strict)"),
                option(
                  { value: "row-by-row" },
                  "Row-by-row (Slower but more accepting)"
                )
              ),
              div(
                { class: "form-check" },
                input({
                  class: "form-check-input",
                  type: "checkbox",
                  id: "import_async",
                  name: "import_async",
                }),
                label(
                  { class: "form-check-label", for: "import_async" },
                  "Asynchronous"
                )
              )
            )
          ),
        },
        {
          type: "card",
          title: req.__(`Preview`),
          contents: div(
            mkTable(
              table.fields.map((f) => ({
                label: f.name,
                key:
                  f.type?.name === "JSON"
                    ? (r) => JSON.stringify(r[f.name])
                    : f.name,
              })),
              full ? rows : rows.slice(0, 10)
            ),
            !full &&
              rows.length > 10 &&
              a(
                {
                  href: `/table/preview_full_csv_file/${
                    table.name
                  }/${path.basename(newPath)}`,
                },
                `See all ${rows.length} rows`
              )
          ),
        },
        ...(parse_res.details
          ? [
              {
                type: "card",
                title: req.__(`Details`),
                contents: pre(parse_res.details),
              },
            ]
          : []),
      ],
    });
  }
}
Delete constraint POST handler
@name post/delete-constraint/:id",
@function
@memberof module:routes/tables~tablesRouter
@function