fix(pdf): stop page tools failing on short and encrypted PDFs (#594)

Empty the hardcoded page-range default in remove/split/extract PDF tools (remove-pages defaulted to "2,4-6", out of range for any PDF under 6 pages) and disable submit until a range is entered. Reject password-protected PDFs up front for PDF-only tools with guidance to unlock first, instead of failing cryptically in the qpdf worker. Adds integration + e2e coverage.
This commit is contained in:
SnapOtter
2026-07-21 06:14:43 +00:00
committed by GitHub
parent 4ba7503f15
commit 73df107758
11 changed files with 173 additions and 9 deletions
@@ -12,7 +12,7 @@ export function ExtractPagesSettings() {
const { processFiles, processAllFiles, processing, error, progress } =
useToolProcessor("extract-pages");
const [range, setRange] = useState("1-3");
const [range, setRange] = useState("");
const hasFile = files.length > 0;
const hasMultiple = files.length > 1;
@@ -36,6 +36,7 @@ export function ExtractPagesSettings() {
id="ep-range"
type="text"
value={range}
placeholder="1-3"
onChange={(e) => setRange(e.target.value)}
className="w-full mt-0.5 px-2 py-1.5 rounded border border-border bg-background text-sm text-foreground"
/>
@@ -58,7 +59,7 @@ export function ExtractPagesSettings() {
type="button"
data-testid="extract-pages-submit"
onClick={handleProcess}
disabled={!hasFile || processing}
disabled={!hasFile || processing || !range.trim()}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed"
>
{hasMultiple ? format(s.submitBatch, { count: files.length }) : s.submit}
@@ -12,7 +12,7 @@ export function RemovePagesSettings() {
const { processFiles, processAllFiles, processing, error, progress } =
useToolProcessor("remove-pages");
const [pages, setPages] = useState("2,4-6");
const [pages, setPages] = useState("");
const hasFile = files.length > 0;
const hasMultiple = files.length > 1;
@@ -36,6 +36,7 @@ export function RemovePagesSettings() {
id="rp-pages"
type="text"
value={pages}
placeholder="2,4-6"
onChange={(e) => setPages(e.target.value)}
className="w-full mt-0.5 px-2 py-1.5 rounded border border-border bg-background text-sm text-foreground"
/>
@@ -58,7 +59,7 @@ export function RemovePagesSettings() {
type="button"
data-testid="remove-pages-submit"
onClick={handleProcess}
disabled={!hasFile || processing}
disabled={!hasFile || processing || !pages.trim()}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed"
>
{hasMultiple ? format(s.submitBatch, { count: files.length }) : s.submit}
@@ -15,7 +15,7 @@ export function SplitPdfSettings() {
useToolProcessor("split-pdf");
const [mode, setMode] = useState<SplitMode>("range");
const [range, setRange] = useState("1-3,5");
const [range, setRange] = useState("");
const [everyN, setEveryN] = useState(1);
const hasFile = files.length > 0;
@@ -97,7 +97,7 @@ export function SplitPdfSettings() {
type="button"
data-testid="split-pdf-submit"
onClick={handleProcess}
disabled={!hasFile || processing}
disabled={!hasFile || processing || (mode === "range" && !range.trim())}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed"
>
{hasMultiple ? format(s.submitBatch, { count: files.length }) : s.submit}