From 45a1bc78b73ac42cf900228c6cbaee0c59f17eb7 Mon Sep 17 00:00:00 2001 From: Jan Eitzinger Date: Tue, 24 Feb 2026 20:26:12 +0100 Subject: [PATCH] Add csv export for user/prject list Fixes #389 --- web/frontend/src/List.root.svelte | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/web/frontend/src/List.root.svelte b/web/frontend/src/List.root.svelte index 239bf5f1..e8af8f44 100644 --- a/web/frontend/src/List.root.svelte +++ b/web/frontend/src/List.root.svelte @@ -61,6 +61,9 @@ } return colbase }) + const sortedRows = $derived( + $stats.data ? sort($stats.data.rows, sorting, nameFilter) : [] + ); let stats = $derived( queryStore({ @@ -87,6 +90,40 @@ ); /* Functions */ + function exportCsv() { + const isUser = type === "USER"; + const header = [ + isUser ? "Username" : "Project", + ...(isUser ? ["Name"] : []), + "Total Jobs", + "Short Jobs", + ...(fetchRunning ? ["Total Cores", "Total Accelerators"] : []), + "Total Walltime", + "Total Core Hours", + "Total Accelerator Hours", + ]; + const rows = sortedRows.map((row) => [ + row.id, + ...(isUser ? [row?.name ?? ""] : []), + row.totalJobs, + row.shortJobs, + ...(fetchRunning ? [row.totalCores, row.totalAccs] : []), + row.totalWalltime, + row.totalCoreHours, + row.totalAccHours, + ]); + const csv = [header, ...rows] + .map((row) => row.map((v) => `"${String(v ?? "").replace(/"/g, '""')}"`).join(",")) + .join("\n"); + const blob = new Blob([csv], { type: "text/csv" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `${type.toLowerCase()}s.csv`; + a.click(); + URL.revokeObjectURL(url); + } + function changeSorting(newField) { if (sorting.field == newField) { // Same Field, Change Direction @@ -137,6 +174,14 @@ PROJECT: 'project', }[type]}" /> +