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]

Reply via email to