Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

plugin-list: the list toolbar Print button is a bare window.print() — no preview, no output, silent no-op in headless/WebView #4462

Closed

Description

@baozhoutao

Reported from an app project (steedos-labs/os-project-titanwind-ehr#1161) on @objectstack/*@17.0.0-rc.6.

What it does

The list view toolbar's Print button is a bare browser print call:

// packages/plugin-list/src/ListView.tsx:2626
onClick={() => window.print()}

No print layout, no preview, no PDF generation, no downloaded artifact. The same bare
call also backs packages/plugin-report/src/ReportViewer.tsx:115 and
packages/app-shell/src/views/DashboardView.tsx:101.

Why it's a defect, not just a thin feature

window.print() is a no-op in exactly the environments a platform gets driven in:
headless/automated browsers and several embedded WebViews. The click resolves normally —
no exception, no console error, nothing rendered. Observed at the reporting project:
the click dispatched successfully, console clean, nothing happened. From the outside it
is indistinguishable from a broken button, and it is being read by acceptance testers as
the product's "export to PDF" entry point.

Even in a normal desktop browser the result is the browser's own dialog printing the
whole Console chrome — unpaginated, tables clipped, styling unsuited to paper (this is
the exact workaround objectstack-ai/objectstack#1301 already documented and rejected as
inadequate).

Repro

  1. Open any object list view in Console.
  2. Click Print in the toolbar.
  3. Headless/WebView: nothing happens, no error. Desktop browser: the browser's print
    dialog for the whole page, including Console chrome.

What we're asking for

Note that the real feature — a print/PDF primitive — was closed NOT_PLANNED as
objectstack-ai/objectstack#1301, so we are not re-litigating that here. Given that
decision, the minimum fix is to stop the button from reading as an export entry point.
In descending order of preference:

  1. Give the list a print stylesheet / print-scoped render so window.print() produces a
    usable page (no Console chrome, paginated, table not clipped).
  2. Document the button's semantics explicitly ("opens your browser's print dialog"; not a
    PDF export), so it stops being accepted against "export PDF" requirements.
  3. Failing both, remove or gate the button rather than ship a control that is a silent
    no-op in a supported runtime.

Related

Activity

  1. self-assigned this
    on Aug 12, 2026
  2. yinlianghui commented on Aug 12, 2026

    @yinlianghui
    Contributor

    CLAIM — session session_017Qqyix2QcnpUC9XeYVDzx3, branch claude/issue-4462-print-usable-page.

    Ruling (delegated authority; open veto window): option 1 + option 2 as a rider; no removal, no headless gating. objectstack#1301 (real PDF primitive) is closed NOT_PLANNED and is not re-litigated; within that constraint:

    1. Make window.print() produce a usable page via a shared @media print stylesheet at the level where the console chrome lives (app-shell global styles — one mechanism, so the same rules serve list, report, and dashboard): hide the shell chrome (nav/header/toolbars) under print; let the active content area print full-width; list table unclipped and paginating (overflow: visible, sensible break-inside rules). Plugin-list gets its own print rules only if the shared sheet measurably can't reach something.
    2. Kill the "export PDF" misreading: the Print buttons on all three surfaces (ListView:2626, ReportViewer:115, DashboardView:101) get a tooltip/aria-label through the existing i18n channel saying it opens the browser's print dialog — not an export. Follow the defaults-map/pack conventions (fix(i18n): the drifted detail row mirrors the en pack, and the three defaults maps get a gate (#4401) #4409's map-mirror gate is live: new keys need their map rows).
    3. No removal, no headless detection — detection is unreliable and a disambiguated button is honest; the headless no-op becomes "documented browser behavior", which is option 2's job.

    Red-first honesty: @media print is not executable in jsdom/happy-dom — pin what IS assertable (the stylesheet ships and contains the chrome-hiding selectors; the buttons carry the new tooltip key through the i18n channel; defaults-map rows exist) and state in-file what cannot red in vitest, the PR #4480 pattern. Do NOT claim a rendered-print pin that cannot fail. Verify the actual print rendering once by browser print-preview screenshot if the environment allows (skill objectui-4462:verify may help); if not, say so.

    Grading: patch per touched package (@object-ui/plugin-list, @object-ui/plugin-report, @object-ui/app-shell) — CSS/tooltip only, .d.ts-checked, never major.

    Surface (mutual exclusion): app-shell global stylesheet + the three named button sites + i18n defaults-maps + tests + changesets. ⛔ Do NOT touch app-shell/src/views/ObjectView.tsx (#4463 in flight), the app-surface/landing components (#4473 in flight), console/organizations/manage/** (#4480 armed), plugin-calendar (#4452 in flight), or the DOM-leak ledger. If the shared sheet's natural home collides with an in-flight file, report instead of editing.


    Generated by Claude Code


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions