Commit Graph
10 Commits
Author SHA1 Message Date
aiongg 08b44e858b fix(ui): keep output file names taken from documents inside the chosen folder
An attachment opened as a tab is named with the same plain file name as
its Save suggestion, and Export certificate names the file the same way
from the certificate subject. Writing files into a chosen folder refuses
any name with a separator, a drive, or that is . or .., so no caller can
write outside the folder.
2026-10-16 18:03:46 +00:00
skylar taylor-barrick b5467d93a0 fix(ui): preserve native open actions and password prompts
Carry selected tool actions through native file preparation, password retries and conversion, and defer startup intake until pending native opens finish.

Await observable completion in native opening, password, recovery and linked-PDF tests while retaining their content, identity, dirty-state, cancellation and destination checks. Verify the expected validation error and preserve the original document after refused consent targets.

M3; refs #1914.
2026-10-13 12:18:41 -06:00
FredAppsandOpenAI Codex 396c9c7836 UI #1114: sanitize suggested attachment save filenames (#1630)
Refs #1114, item 3 only. Preserve stored metadata, payload bytes, and the user-selected destination.

Co-authored-by: OpenAI Codex <noreply@openai.com>
2026-10-13 00:14:32 -04:00
0bc619cd02 Extract pages: a File name field names the extracted files (#737) (#751)
* Extract pages: a File name field names the extracted files (#737)

The Extract pages dialog had no way to name the result: separate files
were always "<document> (page N).pdf" in the chosen folder, and a new
tab was "<document> (extract).pdf".

The dialog now has a File name field, filled in with the document's
name when it opens. Separate files are "<name> (page N).pdf"; a single
renamed page is "<name>.pdf"; extracting into a new tab names the tab
(and so the Save As suggestion) "<name>.pdf". The name is made safe for
every platform (separators, reserved and control characters, trailing
dots and spaces, any-case ".pdf"), and falls back to the document's
name when nothing usable is left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Extract pages: Windows device names get a prefix, and the name is capped at 200 bytes

"NUL.pdf" writes nowhere on Windows, and 200 CJK characters overflow the 255-byte name limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: DWAA1660 <DWAA1660@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-10 08:20:08 -04:00
caeec49f5e M3: keep late startup URLs from changing the active document (#583)
Co-authored-by: Tevinhead <173904641+Tevinhead@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-09 18:52:13 -04:00
966bd0ffce tests: pin the interface language so the suite passes outside English (#502)
The ui-egui integration tests drive the shell by its English labels, and
`i18n::system_lang` returns `Lang::EN` under `cfg!(test)` so they can. That
only covers the unit tests: an integration test links the library as it
ships, where `cfg!(test)` is off, so `PdfCraftApp::new()` leaves `language`
on `auto` and the shell is drawn in the system language. On a Spanish
Windows eleven of the test binaries fail; a French, Russian, Chinese,
Japanese, Portuguese, Czech or Telugu machine does the same. CI never sees
it because its locale is English.

`tests/theme.rs` and `tests/create.rs` already pin the option; the other
119 harnesses now do too, and the comment in `system_lang` says why, so a
test copied from an existing one keeps the line.

Also `i18n::tests::windows_display_language_query_returns_a_locale_tag`
treated the return of `windows_ui_language()` as a single tag. It is the
preferred-language list, one tag per line, as `first_supported` reads it,
so on a Windows with two or more display languages the assertion tripped
over the newline. It now checks the shape of every line.

Co-authored-by: Fernando Areán <soporte@codebit.es>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 09:14:19 -04:00
DWAA1660andClaude Opus 5.5 9fa837e452 Issue #173: a failed ?file= startup fetch is reported in the app (#302)
When the browser app's `?file=` URL couldn't be fetched (an HTTP 404, a
network or CORS failure), the error went only to the developer console and
the user saw the ordinary welcome screen with no sign the PDF was tried.

The fetch now also queues `(name, error)` in a new `failed_inbox` next to
the existing `inbox`, and the app reports it on the next frame with the
notice it already uses for a delivered file that won't open: "Couldn't open
missing.pdf: HTTP 404". The console line stays for developers.

Test: a_failed_startup_url_is_reported_in_the_app (pickers.rs).


Claude-Session: https://claude.ai/code/session_01K3vVft4VXvvy8SpbbUceTW

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:49:25 -04:00
fdadf68085 Web: Insert and Replace edit the document they started on; Print ▸ Save as PDF downloads (#167, #170) (#270)
#167: browser file requests are bound to the document active when the
picker opened (id + edit generation), the same check desktop picks use,
now shared from files.rs. A request that arrives after a switch or an edit
is refused with a notice. Replace keeps that target through its dialog, so
OK never replaces pages in a document opened meanwhile (desktop too).
Browser picks wake the UI once queued, and run under the last-resort guard.

#170: on wasm, Save as PDF downloads "<name> (print).pdf" as Save does,
instead of returning false silently; it never takes the file-system path.
The Print dialog stays open when printing or saving fails.

Co-authored-by: Hal Goff <hal@hg.studio>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 08:54:45 -04:00
fdba8c679a macOS: no blocking file picker left: Save As, exports, folders, Browse… (#145 follow-up) (#262)
Every remaining rfd::FileDialog (26 call sites) ran -[NSSavePanel runModal]
inside winit's event handler, which aborts the app when the window gets an
event while the panel is open. They all go through pickers::ask now: an
rfd::AsyncFileDialog, with the follow-up run as a closure on a later frame.

- One picker at a time, held until its closure starts, so a closure that
  asks again (merge data, run action) gets its picker; refusals are told.
- Closures run inside pdfcraft_engine::guard, as commands do.
- Targets drop a pick if the document is no longer active or was edited.
- Save-on-close closes only once written; CloseRequest::Tab holds a DocId.
- Extract+delete deletes only after writing, and only if unedited.
- Signing happens once the path is chosen, on an unchanged document.
- Browse… results land only in the same showing of the dialog.
- Sign, print-to-PDF and attachment saves write atomically.

Co-authored-by: Hal Goff <hal@hg.studio>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-08 08:26:42 -04:00
d0991a8cd5 macOS: File ▸ Open and file pickers no longer crash the app (#145)
* macOS: File ▸ Open and file pickers no longer crash the app

A blocking rfd::FileDialog runs -[NSOpenPanel runModal], a nested run loop
inside winit's event handler. A mouse or gesture event that arrives while it
spins re-enters the handler, winit panics ("tried to handle event while
another event is currently being handled"), and because the panic can't
unwind out of the AppKit block callback the app aborts.

Open, Combine, Insert pages, Replace pages and OCR ▸ multiple files now use
rfd::AsyncFileDialog, which starts the panel as a sheet and returns at once.
A worker thread waits for the choice and the app uses it on a later frame.
Insert and Replace remember their document and drop a pick that arrives after
the user switched tabs. pick_override lets tests and automation drive these
commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Cargo.lock: pollster for pdfcraft-ui-egui

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 21:37:07 -04:00