Excel Export: Builds .xlsx workbooks from supplied tables or grid panel data and writes/opens them in the plugin's exports folder.
| 1 | import type { BackendContext } from '@jaspers-ai/sdk' |
| 2 | import { buildXlsx } from './xlsx' |
| 3 | import { cleanFilename, defaultFilename, rowArrays, sheetNames } from './sheets' |
| 4 | |
| 5 | export interface TableInput { |
| 6 | title: string |
| 7 | columns: string[] |
| 8 | rows: unknown[] |
| 9 | } |
| 10 | |
| 11 | function base64(bytes: Uint8Array): string { |
| 12 | let s = '' |
| 13 | for (let i = 0; i < bytes.length; i += 0x8000) s += String.fromCharCode(...bytes.subarray(i, i + 0x8000)) |
| 14 | return btoa(s) |
| 15 | } |
| 16 | |
| 17 | /** Builds the workbook, writes it under exports/, opens it, and answers path, sheets, and row counts. */ |
| 18 | export async function writeWorkbook(ctx: BackendContext, tables: TableInput[], filename?: string) { |
| 19 | if (tables.length === 0) throw new Error('No tables to export.') |
| 20 | const names = sheetNames(tables.map((t) => t.title)) |
| 21 | const sheets = tables.map((t, i) => ({ name: names[i]!, columns: t.columns, rows: rowArrays(t.columns, t.rows) })) |
| 22 | const file = filename ? cleanFilename(filename) : defaultFilename(tables[0]!.title, new Date()) |
| 23 | const path = `exports/${file}` |
| 24 | await ctx.files.write(path, base64(buildXlsx(sheets)), { encoding: 'base64' }) |
| 25 | let opened = true |
| 26 | try { |
| 27 | await ctx.files.open(path) |
| 28 | } catch { |
| 29 | opened = false |
| 30 | } |
| 31 | return { |
| 32 | path, |
| 33 | location: `~/Jaspers/excel-export/${path}`, |
| 34 | opened, |
| 35 | sheets: sheets.map((s) => s.name), |
| 36 | rows: sheets.map((s) => ({ sheet: s.name, title: tables[sheets.indexOf(s)]!.title, rows: s.rows.length, columns: s.columns.length })), |
| 37 | } |
| 38 | } |