✨(frontend) Export presenter slides as PDF - #2487
Conversation
|
Size Change: +4.05 kB (+0.09%) Total Size: 4.37 MB 📦 View Changed
|
wrapMediaWithLink / wrapInterlinksWithAnchor defaulted to document. Accept a root node so the presenter export can reuse them on its off-screen tree.
Show a monochrome Docs logo in the slide corner (web and PDF) to signal the document was made with Docs. Closes #2472
Render the slides off-screen as A4 landscape pages and print them via the browser, one slide per page with the watermark. Add a "Download PDF" action to the floating bar. Closes #2446
Exercise PDF print pages, file blocks, and tall slide clipping. Keep coverage scoped to the presenter export workflow.
5882aca to
c1afe04
Compare
WalkthroughPresenter mode now supports PDF export through a new Download PDF action. The export mounts all slides as A4 landscape print pages, adds Docs logo branding, converts media and interlinks for print output, waits for rendering, invokes browser printing, and removes print artifacts afterward. Tests cover component rendering, scoped print wrappers, generated PDF content, file links, tall slides, and cleanup. Estimated code review effort: 4 (Complex) | ~45 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/frontend/apps/impress/src/features/docs/doc-presenter/utils_print.tsx`:
- Around line 137-145: Update printPresenterSlides so it returns a promise that
resolves only when cleanupOnce completes, including the afterprint and
fallback-timer paths. In the export flow, await this promise before clearing
isExportingPdf, keeping the export lock active through cleanup; add a test
covering window.print() returning before afterprint.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bff3960d-f603-45e9-80c4-7301a3fd23df
⛔ Files ignored due to path filters (1)
src/frontend/apps/impress/src/features/docs/doc-presenter/assets/logo-docs-mono.svgis excluded by!**/*.svg
📒 Files selected for processing (9)
src/frontend/apps/e2e/__tests__/app-impress/presenter-mode.spec.tssrc/frontend/apps/impress/src/features/docs/doc-export/__tests__/utilsPrint.test.tssrc/frontend/apps/impress/src/features/docs/doc-export/utils_print.tssrc/frontend/apps/impress/src/features/docs/doc-presenter/__tests__/PresenterPrintDocument.spec.tsxsrc/frontend/apps/impress/src/features/docs/doc-presenter/components/PresenterDocsLogo.tsxsrc/frontend/apps/impress/src/features/docs/doc-presenter/components/PresenterFloatingBar.tsxsrc/frontend/apps/impress/src/features/docs/doc-presenter/components/PresenterOverlay.tsxsrc/frontend/apps/impress/src/features/docs/doc-presenter/components/PresenterPrintDocument.tsxsrc/frontend/apps/impress/src/features/docs/doc-presenter/utils_print.tsx
| try { | ||
| window.addEventListener('afterprint', cleanupOnce, { once: true }); | ||
| await waitForPresenterPrintReady(container); | ||
| scopedCleanups.push(wrapInterlinksWithAnchor(container)); | ||
| scopedCleanups.push(wrapMediaWithLink(container)); | ||
| await nextFrame(); | ||
| window.print(); | ||
| // Fallback in case `afterprint` never fires (some browsers/headless). | ||
| fallbackTimer = window.setTimeout(cleanupOnce, PRINT_CLEANUP_DELAY_MS); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate file and relevant symbols"
fd -a 'utils_print.tsx' . || true
echo
rg -n "printPresenterSlides|PresenterOverlay|isExportingPdf|cleanupOnce|removeExistingPrintArtifacts|afterprint|afterprint|fallbackTimer|PRINT_CLEANUP_DELAY_MS" . -S
echo
file="$(fd 'utils_print.tsx' src/frontend/apps/impress/src/features/docs/doc-presenter | head -n 1 || true)"
if [ -n "$file" ]; then
echo
echo "File: $file"
wc -l "$file"
echo
sed -n '1,240p' "$file" | cat -n
fi
echo
python3 - <<'PY'
from pathlib import Path
p = next(Path('.').rglob('utils_print.tsx'), None)
print('path=', p)
if p:
s=p.read_text()
for name in ['printPresenterSlides', 'cleanupOnce', 'cleanupAll', 'removeExistingPrintArtifacts', 'wrapInterlinksWithAnchor', 'wrapMediaWithLink', 'waitForPresenterPrintReady']:
print(name, 'count=', s.count(name))
PYRepository: suitenumerique/docs
Length of output: 10491
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate file and relevant symbols"
fd -a 'utils_print.tsx' . || true
echo
rg -n "printPresenterSlides|PresenterOverlay|isExportingPdf|cleanupOnce|removeExistingPrintArtifacts|afterprint|fallbackTimer|PRINT_CLEANUP_DELAY_MS" . -S
echo
file="$(fd 'utils_print.tsx' src/frontend/apps/impress/src/features/docs/doc-presenter | head -n 1 || true)"
if [ -n "$file" ]; then
echo
echo "File: $file"
wc -l "$file"
echo
sed -n '1,240p' "$file" | cat -n
fi
echo
python3 - <<'PY'
from pathlib import Path
p = next(Path('.').rglob('utils_print.tsx'), None)
print('path=', p)
if p:
s=p.read_text()
for name in ['printPresenterSlides', 'cleanupOnce', 'cleanupAll', 'removeExistingPrintArtifacts', 'wrapInterlinksWithAnchor', 'wrapMediaWithLink', 'waitForPresenterPrintReady']:
print(name, 'count=', s.count(name))
PYRepository: suitenumerique/docs
Length of output: 10491
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="$(fd 'PresenterOverlay.tsx' src/frontend/apps/impress/src/features/docs/doc-presenter/components | head -n 1 || true)"
if [ -n "$file" ]; then
echo "File: $file"
wc -l "$file"
echo
sed -n '1,180p' "$file" | cat -n
fi
echo
python3 - <<'PY'
from pathlib import Path
p=next(Path('src/frontend/apps/impress/src/features/docs/doc-presenter').rglob('PresenterOverlay.tsx'), None)
text=p.read_text() if p else ''
for name in ['isExportingPdf', 'onExportPdf', 'printPresenterSlides', 'removeExistingPrintArtifacts']:
print(name, text.count(name))
PYRepository: suitenumerique/docs
Length of output: 7412
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="$(fd 'PresenterFloatingBar.tsx' src/frontend/apps/impress/src/features/docs/doc-presenter/components | head -n 1 || true)"
if [ -n "$file" ]; then
echo "File: $file"
wc -l "$file"
echo
sed -n '1,180p' "$file" | cat -n
fi
echo
p="${file:-}"
if [ -n "$p" ]; then
text=$(cat "$p")
for name in ['onExportPdf', 'isDisabled', 'isExportingPdf', 'exportPdf']; do
count=$(printf '%s' "$text" | grep -F -c "$name" || true)
echo "$name -> $count"
done
fiRepository: suitenumerique/docs
Length of output: 6908
Keep the export lock alive until print cleanup finishes.
printPresenterSlides resolves after window.print() returns, while afterprint or the fallback timer may still run. A second export can start once isExportingPdf clears and call mountPresenterPrintSlides(), which removes the previous export’s DOM/style artifacts. Return a promise from printPresenterSlides, resolve it in cleanupOnce, await it before clearing isExportingPdf, and add a test for window.print() returning before afterprint.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/frontend/apps/impress/src/features/docs/doc-presenter/utils_print.tsx`
around lines 137 - 145, Update printPresenterSlides so it returns a promise that
resolves only when cleanupOnce completes, including the afterprint and
fallback-timer paths. In the export flow, await this promise before clearing
isExportingPdf, keeping the export lock active through cleanup; add a test
covering window.print() returning before afterprint.
AntoLC
left a comment
There was a problem hiding this comment.
On the code side, looks good.
I got some problems with the pdf export though, here a video:
Purpose
Refs #2466
Closes #2446
Closes #2472