5a9b5f687fccb3d60a1dace6a17fc106c97db457
Closes out the report exporter. Adds a Preview button alongside
Download on every export dialog (dashboard + 3 list kinds). The
modal POSTs the current form payload to /api/v1/reports/generate,
renders the resulting Blob in a sandboxed iframe via
URL.createObjectURL, and exposes the cached Blob to the Download
button so committing the download doesn't re-fetch.
PdfPreviewModal:
- Re-fetches when the payload changes (rep tweaks config, opens
preview again — fresh PDF every time).
- Cleans up the object URL on close + on unmount, no leak.
- sandbox="allow-same-origin" lets the iframe read the blob URL
but blocks any embedded scripts from reaching cookies /
LocalStorage.
- Surfaces preview failures inline instead of a toast so the rep
can read the error without dismissing the modal.
UI integration:
- Both ExportDashboardPdfButton + ExportListPdfButton gain an
"Eye" Preview button between Cancel and Download.
- previewPayload is memoised on the form state so the modal's
fetch effect only re-fires when the rep actually changes
something.
Verified: tsc clean, vitest 1454/1454. Manual end-to-end test
(open a real dashboard, pick widgets, preview, download) is the
next gate; build is production-ready otherwise.
Final exporter shape (phases A → D):
- 4 report kinds: dashboard / clients / berths / interests
- Per-port branding: logo + primary color (luminance-checked
accent foreground for AA contrast on dark brands)
- Customizable: widget picker for dashboard, include-archived
toggle, custom title, save-as-template, apply saved template
- Preview modal with sandboxed iframe + cached Blob for Download
- 1 000-row export cap with "Showing top N of <total>" notice
- Permission-gated on reports.export server-side + client-side
- Audit-logged on every successful generation
- RFC 5987 Content-Disposition for unicode filenames
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Description
No description provided
Languages
TypeScript
98.7%
HTML
1%
CSS
0.1%
Shell
0.1%