Stage 2 live print panel — unmanaged spool UI (#17) #47

Merged
gronod merged 2 commits from feat/17-print-panel-ui into milestone/m3-printing 2026-09-09 07:07:13 +01:00
Owner

Live #rawPrintPanel in Stage 2 — unmanaged lp spool path (docs/11/21):

  • Controls: printerSelect (lpstat -e, auto-refresh when the manifest lands), printerStatusBadge (idle/printing/stopped from lpstat -p), printerTraySelect + printerMediaTypeSelect from lpoptions -l capabilities, btnOrientPortrait/btnOrientLandscape, btnPrinterProperties (⚙︎ → bound NSPrintPanel), btnPrintAll + per-page btnPrintPage-N, in-panel printNotification (cancel → info, not error).
  • Not present on macOS: cupsOptionsGroup/chkPpdFallback — the PM-captured path is always used.
  • Preferences flow: cancel → info notice + no cache mutation; OK → captured options stored per-queue in capturedCupsOptions (session cache); a panel-side queue switch updates printerSelect when the returned CUPS id is in the list.
  • Spooling: sequential CupsService.printTarget per page, stop-on-first-error; wizardState.printerName recorded (#95).
  • Parser fix: lpoptions no longer truncates on a keyless =value token.

UI tests (Milestone3UITests): enumeration, cancel→info, captured options replayed in lp argv, per-page print, lp failure notice, printerName persistence — with mock lpstat/lpoptions/lp fixtures and the ICCERY_TEST_PRINT_PANEL stub.

⚠️ Not run here: the dev machine's console was locked (IOConsoleLocked=true) — XCUIApplication.activate() cannot bring the app to front (verified identical failure on the M2 baseline). The suite must run unlocked or on CI. Core tests: 154 pass.

Closes #17.

Generated with Devin

Live `#rawPrintPanel` in Stage 2 — unmanaged `lp` spool path (docs/11/21): - **Controls**: `printerSelect` (lpstat -e, auto-refresh when the manifest lands), `printerStatusBadge` (idle/printing/stopped from `lpstat -p`), `printerTraySelect` + `printerMediaTypeSelect` from `lpoptions -l` capabilities, `btnOrientPortrait`/`btnOrientLandscape`, `btnPrinterProperties` (⚙︎ → bound `NSPrintPanel`), `btnPrintAll` + per-page `btnPrintPage-N`, in-panel `printNotification` (cancel → **info**, not error). - **Not present** on macOS: `cupsOptionsGroup`/`chkPpdFallback` — the PM-captured path is always used. - **Preferences flow**: cancel → info notice + no cache mutation; OK → captured options stored per-queue in `capturedCupsOptions` (session cache); a panel-side queue switch updates `printerSelect` when the returned CUPS id is in the list. - **Spooling**: sequential `CupsService.printTarget` per page, stop-on-first-error; `wizardState.printerName` recorded (#95). - **Parser fix**: `lpoptions` no longer truncates on a keyless `=value` token. **UI tests** (`Milestone3UITests`): enumeration, cancel→info, captured options replayed in `lp` argv, per-page print, `lp` failure notice, `printerName` persistence — with mock `lpstat`/`lpoptions`/`lp` fixtures and the `ICCERY_TEST_PRINT_PANEL` stub. ⚠️ **Not run here**: the dev machine's console was locked (`IOConsoleLocked=true`) — `XCUIApplication.activate()` cannot bring the app to front (verified identical failure on the M2 baseline). The suite must run unlocked or on CI. Core tests: 154 pass. Closes #17. Generated with [Devin](https://devin.ai)
gronod added the Kind/Feature
Priority
High
2
Project/ICCery-v2Feature/Backend
labels 2026-09-09 01:19:34 +01:00
gronod added 1 commit 2026-09-09 01:19:34 +01:00
- rawPrintPanel: printerSelect (lpstat -e, auto-refresh on manifest),
  printerStatusBadge (idle/printing/stopped), printerTraySelect +
  printerMediaTypeSelect from lpoptions -l capabilities, portrait/
  landscape toggle, btnPrinterProperties (bound NSPrintPanel), Print
  All + per-page btnPrintPage-N, in-panel printNotification (cancel →
  info, not error). No cupsOptionsGroup/chkPpdFallback — macOS always
  uses the PM-captured path.
- TargetWorkflowViewModel: refreshPrinters, reloadSelectedCapabilities,
  openPrinterPreferences (panel-side queue switch updates the select),
  printAllPages / printPage (sequential, stop-on-first-error),
  capturedCupsOptions per-queue session cache, wizard.printerName set
  on spool (#95).
- CupsError.noPrinterSelected.
- Mock CUPS fixtures: lpstat (2 queues, one idle one disabled),
  lpoptions (tray/media/EPIJ_CMat listings), lp (appends argv to
  ICCERY_TEST_LP_ARGV). Milestone3UITests: enumeration, preferences
  cancel→info, captured options replayed in argv, per-page print,
  lp failure notice, printerName persistence.
- lpoptions parser: skip keyless '=value' tokens instead of truncating.

UI tests written but not executed here: the dev machine's console is
locked (IOConsoleLocked=true) so XCUIApplication.activate() cannot
bring the app to front — same failure on M2 baseline. Suite must be
run unlocked / on CI.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
gronod added 1 commit 2026-09-09 07:07:07 +01:00
- Ensure unstructured Task closures in TargetWorkflowViewModel and
  Stage2View run on @MainActor after awaiting CupsService / spool.
  Without this,  updates in the  failure path were
  not reaching the UI in time, failing Milestone3UITests.
- lpoptions parser: a  token no longer truncates the whole
  parse.

UI test results: Milestone3UITests 6/6 pass; Core tests 154/154 pass;
universal arm64 x86_64 build passes.
gronod merged commit ad6f8247d2 into milestone/m3-printing 2026-09-09 07:07:13 +01:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gronod/iccery-v2-mac#47