6ede33ccdb
Build and Push Docker Images / create_manifest (web, surfsense-web, , cpu) (push) Has been cancelled
Build and Push Docker Images / finalize_release (push) Has been cancelled
Obsidian Plugin Lint / lint (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_web, cpu, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-24.04-arm, linux/arm64, arm64, , runner, false, cpu) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_web, cpu, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-latest, linux/amd64, amd64, , runner, false, cpu) (push) Has been cancelled
Build and Push Docker Images / compute_version (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cpu, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, , production, false, cpu) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cpu, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, , production, false, cpu) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu126, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, -cuda126, production, true, cuda126) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu126, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, -cuda126, production, true, cuda126) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu128, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, -cuda, production, true, cuda) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu128, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, -cuda, production, true, cuda) (push) Has been cancelled
Build and Push Docker Images / verify_digests (push) Has been cancelled
Build and Push Docker Images / create_manifest (backend, surfsense-backend, , cpu) (push) Has been cancelled
Build and Push Docker Images / create_manifest (backend, surfsense-backend, -cuda, cuda) (push) Has been cancelled
Build and Push Docker Images / create_manifest (backend, surfsense-backend, -cuda126, cuda126) (push) Has been cancelled
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
/** CSV export helpers for the playground runs table and API output tables. */
|
|
|
|
function cellToString(value: unknown): string {
|
|
if (value === null || value === undefined) return "";
|
|
if (typeof value === "object") return JSON.stringify(value);
|
|
return String(value);
|
|
}
|
|
|
|
// Leading chars a spreadsheet treats as the start of a formula. Scraped API
|
|
// data is untrusted, so we neutralize these to prevent CSV injection.
|
|
const FORMULA_START = /^[=+@\t\r]/;
|
|
const LOOKS_NUMERIC = /^-?\d/;
|
|
|
|
function escapeCsvCell(value: unknown): string {
|
|
let s = cellToString(value);
|
|
if (FORMULA_START.test(s) || (s.startsWith("-") && !LOOKS_NUMERIC.test(s))) {
|
|
s = `'${s}`;
|
|
}
|
|
if (/[",\n\r]/.test(s)) {
|
|
s = `"${s.replace(/"/g, '""')}"`;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Serialize rows to an RFC 4180 CSV string. Columns default to the union of
|
|
* keys across all rows (stable insertion order); pass ``columns`` to fix the
|
|
* order and subset.
|
|
*/
|
|
export function rowsToCsv(rows: Record<string, unknown>[], columns?: string[]): string {
|
|
const cols =
|
|
columns ??
|
|
Array.from(
|
|
rows.reduce((set, row) => {
|
|
for (const key of Object.keys(row)) set.add(key);
|
|
return set;
|
|
}, new Set<string>())
|
|
);
|
|
const header = cols.map(escapeCsvCell).join(",");
|
|
if (rows.length === 0) return header;
|
|
const body = rows.map((row) => cols.map((col) => escapeCsvCell(row[col])).join(",")).join("\r\n");
|
|
return `${header}\r\n${body}`;
|
|
}
|
|
|
|
/** Trigger a browser download of ``csv`` as ``{filenameBase}.csv`` (UTF-8, Excel-friendly). */
|
|
export function downloadCsv(filenameBase: string, csv: string): void {
|
|
const safe = filenameBase.replace(/[^\w.-]+/g, "_") || "export";
|
|
// Prepend a BOM so Excel detects UTF-8.
|
|
const blob = new Blob([`\uFEFF${csv}`], { type: "text/csv;charset=utf-8" });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = `${safe}.csv`;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
}
|