Files
supabase/apps/studio/components/interfaces/Explorer/NotebookPdf/exportNotebookToPdf.tsx
T
Joshen Lim 38fa40e851 Joshenlim/fe 4445 explorer export as pdf option 2 (#50786)
## Context

Another take on [this
PR](https://github.com/supabase/supabase/pull/50733), decided that it's
better UX + DX to use a PDF library (`@react-pdf/renderer`) instead for
handling exporting Notebooks to PDF. The previous method using `print`
involved a lot of sparse patching in various places + had a lot of
limitations, not to mention its awkward UX to "Print".

There's a lot of code changes in this PR but it's because we're
constructing the PDF document based on the notebook's contents using
primitives from `@react-pdf/renderer` which gives us a lot more control
over the PDF's output.

PDF output will differ slightly from the Notebook UI in the browser
- Added a custom header in the report which covers the notebook name +
project name, and when its exported
- Empty markdown cells are skipped
- Query cells will show both SQL content + results (either table or
chart)
- Opting to skip syntax highlighting for SQL content (Can consider
separately)
- Results will only be included in the PDF if the notebook's been run
(Aligns with Copy as Markdown CTA)
- For table results, _all_ rows will be rendered (Aligns with Copy as
Markdown CTA)

Feel free to give it a spin! 🙂 🙏 

<img width="248" height="207" alt="image"
src="https://github.com/user-attachments/assets/e38c14ba-7ee8-40ce-99b1-fa126453bf0f"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Added an “Export as PDF” option for notebooks.
- PDFs include notebook details, Markdown content, SQL queries, query
results, tables, and charts.
- Query exports show errors, empty results, row counts, and applicable
row limits.
- Export progress is displayed while the PDF is generated, and failures
are reported via notifications.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-24 13:23:38 +08:00

40 lines
1.3 KiB
TypeScript

import { pdf } from '@react-pdf/renderer'
import saveAs from 'file-saver'
import type { Snapshot } from 'valtio'
import { type QueryResult } from '../types'
import { NotebookPdfDocument } from './NotebookPdfDocument'
import { isQueryCell, type Cell } from '@/data/content/notebooks/notebook-schema'
export interface ExportNotebookToPdfParams {
name: string
projectName?: string
cells: readonly Snapshot<Cell>[]
getResult: (cellId: string) => QueryResult | undefined
}
/**
* Gathers a notebook's cells and each query cell's last in-session result — results aren't
* persisted with the notebook, so they're read off the same `queryCellRefs` imperative
* handles `notebookToMarkdown` (ExplorerNotebookTab.utils.ts) already uses — then renders
* and downloads a PDF report.
*/
export async function exportNotebookToPdf({
name,
projectName,
cells,
getResult,
}: ExportNotebookToPdfParams): Promise<void> {
const results = new Map<string, QueryResult>()
cells.filter(isQueryCell).forEach((cell) => {
const result = getResult(cell._id)
if (result) results.set(cell._id, result)
})
const blob = await pdf(
<NotebookPdfDocument name={name} projectName={projectName} cells={cells} results={results} />
).toBlob()
saveAs(blob, `${name}.pdf`)
}