From 6d72ee795f2cacb72cc8fee9cc6f15acd34cbd67 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 11 Aug 2025 10:29:48 -0700 Subject: [PATCH] Feature: PDF editor (#10318) --- docs/api.md | 12 + docs/usage.md | 10 +- src-ui/setup-jest.ts | 20 ++ ...delete-pages-confirm-dialog.component.html | 54 ----- ...delete-pages-confirm-dialog.component.scss | 28 --- ...ete-pages-confirm-dialog.component.spec.ts | 60 ----- .../delete-pages-confirm-dialog.component.ts | 69 ------ .../split-confirm-dialog.component.html | 59 ----- .../split-confirm-dialog.component.scss | 9 - .../split-confirm-dialog.component.spec.ts | 107 --------- .../split-confirm-dialog.component.ts | 98 -------- .../pdf-editor/pdf-editor.component.html | 103 +++++++++ .../pdf-editor/pdf-editor.component.scss | 70 ++++++ .../pdf-editor/pdf-editor.component.spec.ts | 142 ++++++++++++ .../common/pdf-editor/pdf-editor.component.ts | 133 +++++++++++ .../document-detail.component.html | 12 +- .../document-detail.component.spec.ts | 74 ++---- .../document-detail.component.ts | 112 ++------- src/documents/bulk_edit.py | 97 ++++++++ src/documents/serialisers.py | 53 ++++- src/documents/tests/test_api_bulk_edit.py | 213 ++++++++++++++++++ src/documents/tests/test_bulk_edit.py | 153 +++++++++++++ src/documents/views.py | 40 ++-- 23 files changed, 1066 insertions(+), 662 deletions(-) delete mode 100644 src-ui/src/app/components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component.html delete mode 100644 src-ui/src/app/components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component.scss delete mode 100644 src-ui/src/app/components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component.spec.ts delete mode 100644 src-ui/src/app/components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component.ts delete mode 100644 src-ui/src/app/components/common/confirm-dialog/split-confirm-dialog/split-confirm-dialog.component.html delete mode 100644 src-ui/src/app/components/common/confirm-dialog/split-confirm-dialog/split-confirm-dialog.component.scss delete mode 100644 src-ui/src/app/components/common/confirm-dialog/split-confirm-dialog/split-confirm-dialog.component.spec.ts delete mode 100644 src-ui/src/app/components/common/confirm-dialog/split-confirm-dialog/split-confirm-dialog.component.ts create mode 100644 src-ui/src/app/components/common/pdf-editor/pdf-editor.component.html create mode 100644 src-ui/src/app/components/common/pdf-editor/pdf-editor.component.scss create mode 100644 src-ui/src/app/components/common/pdf-editor/pdf-editor.component.spec.ts create mode 100644 src-ui/src/app/components/common/pdf-editor/pdf-editor.component.ts diff --git a/docs/api.md b/docs/api.md index 7b525efaa..cd3e462da 100644 --- a/docs/api.md +++ b/docs/api.md @@ -282,6 +282,18 @@ The following methods are supported: - `"merge": true or false` (defaults to false) - The `merge` flag determines if the supplied permissions will overwrite all existing permissions (including removing them) or be merged with existing permissions. +- `edit_pdf` + - Requires `parameters`: + - `"doc_ids": [DOCUMENT_ID]` A list of a single document ID to edit. + - `"operations": [OPERATION, ...]` A list of operations to perform on the documents. Each operation is a dictionary + with the following keys: + - `"page": PAGE_NUMBER` The page number to edit (1-based). + - `"rotate": DEGREES` Optional rotation in degrees (90, 180, 270). + - `"doc": OUTPUT_DOCUMENT_INDEX` Optional index of the output document for split operations. + - Optional `parameters`: + - `"delete_original": true` to delete the original documents after editing. + - `"update_document": true` to update the existing document with the edited PDF. + - `"include_metadata": true` to copy metadata from the original document to the edited document. - `merge` - No additional `parameters` required. - The ordering of the merged document is determined by the list of IDs. diff --git a/docs/usage.md b/docs/usage.md index 73d3336ce..9310d9a2f 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -580,12 +580,14 @@ The following custom field types are supported: ## PDF Actions -Paperless-ngx supports four basic editing operations for PDFs (these operations currently cannot be performed on non-PDF files): +Paperless-ngx supports basic editing operations for PDFs (these operations currently cannot be performed on non-PDF files). When viewing an individual document you can +open the 'PDF Editor' to use a simple UI for re-arranging, rotating, deleting pages and splitting documents. - Merging documents: available when selecting multiple documents for 'bulk editing'. -- Rotating documents: available when selecting multiple documents for 'bulk editing' and from an individual document's details page. -- Splitting documents: available from an individual document's details page. -- Deleting pages: available from an individual document's details page. +- Rotating documents: available when selecting multiple documents for 'bulk editing' and via the pdf editor on an individual document's details page. +- Splitting documents: via the pdf editor on an individual document's details page. +- Deleting pages: via the pdf editor on an individual document's details page. +- Re-arranging pages: via the pdf editor on an individual document's details page. !!! important diff --git a/src-ui/setup-jest.ts b/src-ui/setup-jest.ts index c24762313..c52c00647 100644 --- a/src-ui/setup-jest.ts +++ b/src-ui/setup-jest.ts @@ -121,6 +121,26 @@ if (!URL.revokeObjectURL) { } Object.defineProperty(window, 'ResizeObserver', { value: mock() }) +if (typeof IntersectionObserver === 'undefined') { + class MockIntersectionObserver { + constructor( + public callback: IntersectionObserverCallback, + public options?: IntersectionObserverInit + ) {} + + observe = jest.fn() + unobserve = jest.fn() + disconnect = jest.fn() + takeRecords = jest.fn() + } + + Object.defineProperty(window, 'IntersectionObserver', { + writable: true, + configurable: true, + value: MockIntersectionObserver, + }) +} + HTMLCanvasElement.prototype.getContext = < typeof HTMLCanvasElement.prototype.getContext >jest.fn() diff --git a/src-ui/src/app/components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component.html b/src-ui/src/app/components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component.html deleted file mode 100644 index 01bf5d3fd..000000000 --- a/src-ui/src/app/components/common/confirm-dialog/delete-pages-confirm-dialog/delete-pages-confirm-dialog.component.html +++ /dev/null @@ -1,54 +0,0 @@ -
{{message}}
-