# LIS — On-screen report preview (Validation worklist)

**Status:** ✅ SHIPPED on `hazemdev` + FF'd to `main` (2026-06-26). FE deployed to `/app`. Reaches elmadina + every lab via the normal MoonStack update (no DB change — pure FE).
**Commits:** FE `1339b3b` · CHANGELOG `04ed881d2`.

## Why (the problem)
On `/lab/validation` you could only **Print** a report (opens a PDF tab / print window) — there was no way to *see what the report looks like inside* before validating/editing/releasing. The owner hit this on `elmadina LR-2026-00003` and noted it happens "with this type of report".

Root cause of "this type": a preview component **did** exist (`LisResultPreviewComponent`, route `…/results/:id/preview`) but:
1. it was **orphaned** — only linked from the **retired** results page, never reachable from Validation; and
2. its own `buildReportData()` handled **only panels + plain numeric/text rows** — it did **NOT** render the rich result types (**culture/sensitivity, histopathology, narrative/memo, file/image** attachments), dumping raw JSON or `-`. So exactly the reports that most need a visual review previewed worst.

## The fix — reuse the canonical print engine
Instead of reviving the divergent builder, the preview now renders through the **same engine as Print**, so it's byte-identical to the printed report and handles every type.

- **`LisHtmlReportService.buildReportHtml(...)`** (new public) — returns the report HTML string. `printReport()` now delegates to it (pure refactor).
- **`LisPrintReportService`**:
  - `_render(reqId, templateOverride?, onlyInvIds?, includeDraft?, preview?)` — new `preview` flag; in the HTML-template branch it returns `{ html:true, htmlString }` (via `buildReportHtml`) instead of opening a window. Classic branch is untouched (`{ doc }`).
  - **`previewRequest(reqId, templateOverride?, onlyInvIds?, includeDraft=true)`** (new public) → `{kind:'pdf',url} | {kind:'html',html} | null`. `url` is `doc.output('bloburl')` for classic; the HTML path is wrapped into a blob URL by the caller.
  - **Print path (`printRequest`/`generateDoc`) is provably unchanged** — `preview` defaults `false`.
- **`ValidationWorklistComponent`**:
  - `previewReport()` calls `previewRequest`, turns both PDF/HTML into a **blob URL**, sanitizes via `bypassSecurityTrustResourceUrl`, shows it in a `<p-dialog>` `<iframe [src]>`. (HTML → blob URL avoids fighting Angular's `srcdoc` sanitizer.)
  - `closePreview()` / `revokePreviewUrl()` free the object URL; revoked on close + `ngOnDestroy` + a **closed-dialog race guard** (if the dialog was dismissed during the await, the freshly-created URL is revoked and we bail).
  - `canPreview` computed → button shows once any result is **past `pending`** (entered/validated/approved/released), so you can preview **before release**.
  - **`includeDraft=true`** → the preview includes not-yet-released results, watermarked **DRAFT**, so reviewers see the full current report before signing off.
  - Button: `pi-eye` "معاينة/Preview" next to Print.

## Key decisions / gotchas
- **Preview = blob URL in an iframe** for BOTH PDF and HTML (uniform, same-origin, no srcdoc sanitizer issues). jsPDF's `output('bloburl')` already does `createObjectURL`; `URL.revokeObjectURL` on it is the correct/complete cleanup.
- The generated report HTML contains **no embedded `<script>`/auto-print** (the print trigger is external in `printReport`), so the iframe just renders — no stray print dialog.
- The old `LisResultPreviewComponent` is now fully superseded for Validation; it remains orphaned (left as-is, out of scope to delete).
- Pure FE — **no migration**, reaches all labs via update.

## Review
Native code-reviewer (Codex blocked on this server): **APPROVE**, 0 critical/high/medium. 3 LOW applied before commit: catch-block URL revoke, `_render` JSDoc, removal of a stale unused `LisHtmlReportService` injection in the component.
