ShauryaaIBM opened a new pull request, #43755:
URL: https://github.com/apache/superset/pull/43755
### SUMMARY
Replaces the raster-screenshot-stitched PDF path for dashboard reports with
Playwright's native \`page.pdf()\`, producing **vector PDFs with selectable
text**. The feature is strictly additive: it is gated by a new feature flag
(\`DASHBOARD_REPORTS_BROWSER_PRINT_PDF\`, default \`False\`) and any failure
falls back transparently to the existing screenshot path. There is **no
behaviour change for existing deployments**.
#### How it works
When both \`PLAYWRIGHT_REPORTS_AND_THUMBNAILS\` and
\`DASHBOARD_REPORTS_BROWSER_PRINT_PDF\` are enabled and a dashboard PDF report
runs:
1. A \`DashboardPrintScreenshot\` instance appends \`?print=1&standalone=3\`
(plus optional font-size, layout, orientation params) to the dashboard URL.
2. Playwright navigates at a 1600 px viewport so ECharts/canvas elements
draw at their design resolution.
3. The frontend (\`DashboardBuilder\`) detects \`?print=1\`, adds
\`body.print-mode\`, and injects combined CSS: base print-mode rules +
font-size tier overrides + layout CSS + orientation CSS.
4. A sequence of JavaScript mutations prepares the DOM for \`page.pdf()\`:
- \`UNHIDE_TAB_PANELS_JS\` — removes \`display:none\` from tab panels
hidden by antd CSSMotion.
- \`PRINT_ALL_CHART_HOLDERS_READY_JS\` — waits for every chart holder
(not just viewport-visible) to reach a terminal state.
- \`SHOW_ALL_TABLE_ROWS_JS\` — fires \`onChange(0)\` on every
client-side-paginated table's antd Select to expand all rows before capture.
- \`EXPAND_TABLE_CONTAINERS_JS\` — releases inline height/overflow and
any inline pixel width from scroll-container divs so all rows and columns are
visible. The \`hasInlineWidth\` condition (any \`width:Xpx\` inline, regardless
of overflow style) correctly handles the useSticky header-sizer chain whose
divs carry a pixel width with no overflow property.
- \`MEASURE_TABLE_COLUMNS_JS\` + \`BAND_TABLE_COLUMNS_JS\` — for tables
too wide to fit on one page, greedy-packs columns into page-width bands (each a
standalone \`<table>\` with key + band columns) with key columns repeated.
Falls through to the scale step for tables that need only a single band.
- \`SCALE_WIDE_TABLES_JS\` — applies a CSS \`transform:scale()\` to the
scroll-container of tables that still exceed the viewport after banding, or
marks them \`data-print-landscape="true"\` in \`auto\` orientation mode.
- \`SET_PRINT_FONT_SIZE_JS\` — patches \`font-size\` on \`.header-line\`
elements (Big Number charts use React inline styles that CSS \`!important\`
cannot override). Fires for all three tiers.
- \`ANNOTATE_PRINT_COLUMNS_JS\` — tags \`.dragdroppable-column\` elements
with flex-grow weights for the optional 2-column adaptive layout.
5. Header/footer templates are built. Per-report content (from
\`extra.dashboard\`) takes precedence over the global
\`BROWSER_PRINT_PDF_HEADER_CONTENT\` / \`_FOOTER_CONTENT\` config. All
user-supplied strings are HTML-escaped to prevent injection; only the Chromium
\`<span class="date">\` element is emitted unescaped.
6. \`page.pdf(format="A4", scale=794/1600, print_background=True,
display_header_footer=True, …)\` produces the final PDF.
#### Per-report configuration (Alerts & Reports modal)
When the feature flag is enabled and a PDF dashboard report is being
configured, the following controls appear in the **Report contents** panel:
| Control | Stores in |
|---|---|
| PDF font size (Small / Medium / Large) | \`extra.dashboard.pdf_font_size\`
|
| PDF orientation (Portrait / Landscape / Auto) |
\`extra.dashboard.pdf_orientation\` |
| Use 2-column adaptive layout | \`extra.dashboard.pdf_layout\` |
| PDF header left / right slots | \`extra.dashboard.pdf_header\` |
| PDF footer left / center slots | \`extra.dashboard.pdf_footer\` |
Each per-report value overrides the corresponding global config key when set.
#### Font size tiers (CSS px at 1600 px viewport)
| Tier | Table td/th | Chart title | Big Number (JS patch) |
|---|---|---|---|
| small (default) | 16 px (~8 pt) | 22 px (~11 pt) | 48 px (~9 pt) |
| medium | 24 px (~12 pt) | 32 px (~16 pt) | 72 px (~14 pt) |
| large | 36 px (~18 pt) | 44 px (~22 pt) | 108 px (~21 pt) |
#### New config keys (all optional, all have safe defaults)
```python
DASHBOARD_REPORTS_BROWSER_PRINT_PDF = False # master switch; default off
BROWSER_PRINT_PDF_FONT_SIZE = None # str | None; None → 'small'
BROWSER_PRINT_PDF_LAYOUT = None # str | None; None → '1col'
BROWSER_PRINT_PDF_ORIENTATION = None # str | None; None → portrait
BROWSER_PRINT_PDF_VIEWPORT_WIDTH = 1600 # int
BROWSER_PRINT_PDF_HEADER_FOOTER = True # bool; False disables
header/footer
BROWSER_PRINT_PDF_HEADER_CONTENT = {...} # dict[str, str] | None
BROWSER_PRINT_PDF_FOOTER_CONTENT = {...} # dict[str, str] | None
```
Header/footer slots support \`{title}\` (HTML-escaped dashboard title) and
\`{date}\` (Chromium date span) tokens.
#### New dependency
\`pypdf==6.16.2\` added to \`requirements/base.txt\` for future multi-tab
PDF merging. The import is inside a \`try/except ImportError\` block so the
single-URL render path is used when pypdf is unavailable.
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
**Before:** PDF reports are produced by stitching together raster PNG
screenshots. Text is not selectable; table rows are often cut mid-row at page
boundaries; wide tables with many columns are clipped.
**After (flag enabled):** PDF reports are produced by \`page.pdf()\`. Text
is selectable vector output. Tables expand to show all rows before capture.
Wide tables are banded into per-page column groups or scaled to fit. Per-page
header and footer with dashboard title, date, and page numbering are stamped
automatically.
### TESTING INSTRUCTIONS
1. Enable both feature flags in \`superset_config.py\`:
```python
FEATURE_FLAGS = {
"PLAYWRIGHT_REPORTS_AND_THUMBNAILS": True,
"DASHBOARD_REPORTS_BROWSER_PRINT_PDF": True,
}
```
2. Ensure Playwright is installed: \`pip install playwright && playwright
install chromium\`.
3. Create a Report targeting a dashboard, set format to **PDF**, and trigger
it.
4. Verify the emailed/Slack attachment is a PDF with selectable text.
5. (Optional) Test per-report PDF options in the Alerts & Reports modal.
6. Disable \`DASHBOARD_REPORTS_BROWSER_PRINT_PDF\` and confirm the report
still works via the screenshot fallback.
**Automated tests:**
```bash
# Python (all mocked, no browser required)
pytest tests/unit_tests/utils/test_browser_print_pdf.py -v # 31 tests
# Jest
cd superset-frontend
npx jest "src/dashboard/components/__tests__/printModeLogic.test.ts"
--no-coverage # 22 tests
```
### ADDITIONAL INFORMATION
- [x] Required feature flags: \`DASHBOARD_REPORTS_BROWSER_PRINT_PDF\`
(default \`False\`) + pre-existing \`PLAYWRIGHT_REPORTS_AND_THUMBNAILS\`
- [x] Changes UI: adds PDF options block in Alerts & Reports modal (visible
only when flag is enabled, format is PDF, content type is dashboard)
- [x] Introduces new feature or API: \`DashboardPrintScreenshot\`,
\`WebDriverPlaywright.get_print_pdf()\`, and related config keys
- [ ] Has associated issue:
- [ ] Includes DB Migration
- [ ] Removes existing feature or API
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]