download-table.ts1.6 KBView on GitHub /**
* "Download as Excel" / "Download as CSV" for a table document.
*
* The server side is the whole implementation — `documents.exportTable` runs exceljs and
* returns `{ filename, mimeType, base64 }`. All that is left on the client is turning that
* into a Blob and clicking a link, which is here rather than inline in two callers (the
* table toolbar and the `FileEditor` dropdown) so the two cannot produce differently-named
* files.
*/
import { base64ToUint8Array } from '@/modules/documents/yjs';
export type TableExportFormat = 'xlsx' | 'csv';
export interface TableExportResult {
filename: string;
mimeType: string;
base64: string;
}
/** The client surface `saveTableExport` needs — narrowed so callers can pass a test double. */
export interface TableExportClient {
documents: {
exportTable: {
query: (input: {
documentId: string;
format: TableExportFormat;
}) => Promise<TableExportResult>;
};
};
}
export async function downloadTableExport(
client: TableExportClient,
documentId: string,
format: TableExportFormat,
): Promise<void> {
const result = await client.documents.exportTable.query({ documentId, format });
const blob = new Blob([base64ToUint8Array(result.base64)], { type: result.mimeType });
const url = URL.createObjectURL(blob);
try {
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = result.filename;
anchor.click();
} finally {
// Revoked on a later task: Safari reads the blob asynchronously after the click, and
// revoking synchronously produces an empty download.
setTimeout(() => URL.revokeObjectURL(url), 60_000);
}
}