From e389298aab8e32d71b3cfe5f2ea1b1407aaa3243 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 19 Aug 2026 07:20:14 -0700 Subject: [PATCH] Enhancement: merge documents as versions (#13515) --- docs/api.md | 1 + docs/usage.md | 4 + ...-as-versions-confirm-dialog.component.html | 58 ++ ...-as-versions-confirm-dialog.component.scss | 3 + ...-versions-confirm-dialog.component.spec.ts | 70 +++ ...ge-as-versions-confirm-dialog.component.ts | 70 +++ .../merge-confirm-dialog.component.html | 2 +- .../document-detail.component.spec.ts | 20 +- .../document-detail.component.ts | 11 +- ...ing-document-version-dialog.component.html | 18 + ...-document-version-dialog.component.spec.ts | 73 +++ ...sting-document-version-dialog.component.ts | 35 ++ .../document-version-dropdown.component.html | 27 +- ...ocument-version-dropdown.component.spec.ts | 60 +- .../document-version-dropdown.component.ts | 60 +- .../bulk-editor/bulk-editor.component.html | 3 + .../bulk-editor/bulk-editor.component.spec.ts | 83 +++ .../bulk-editor/bulk-editor.component.ts | 46 +- .../services/rest/document.service.spec.ts | 28 + .../src/app/services/rest/document.service.ts | 12 + src-ui/src/main.ts | 2 + src/documents/bulk_edit.py | 114 ++++ src/documents/models.py | 10 +- src/documents/serialisers.py | 55 +- .../tests/test_api_document_versions.py | 61 ++ src/documents/tests/test_api_schema.py | 1 + .../tests/test_merge_documents_as_versions.py | 546 ++++++++++++++++++ src/documents/versioning.py | 24 +- src/documents/views.py | 54 +- src/paperless/urls.py | 6 + 30 files changed, 1504 insertions(+), 53 deletions(-) create mode 100644 src-ui/src/app/components/common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component.html create mode 100644 src-ui/src/app/components/common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component.scss create mode 100644 src-ui/src/app/components/common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component.spec.ts create mode 100644 src-ui/src/app/components/common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component.ts create mode 100644 src-ui/src/app/components/document-detail/document-version-dropdown/add-existing-document-version-dialog/add-existing-document-version-dialog.component.html create mode 100644 src-ui/src/app/components/document-detail/document-version-dropdown/add-existing-document-version-dialog/add-existing-document-version-dialog.component.spec.ts create mode 100644 src-ui/src/app/components/document-detail/document-version-dropdown/add-existing-document-version-dialog/add-existing-document-version-dialog.component.ts create mode 100644 src/documents/tests/test_merge_documents_as_versions.py diff --git a/docs/api.md b/docs/api.md index b8ba5fc35..58927229d 100644 --- a/docs/api.md +++ b/docs/api.md @@ -227,6 +227,7 @@ Version-aware endpoints: - `PATCH /api/documents/{id}/`: content updates target the selected version (`?version={version_id}`) or latest version by default; non-content metadata updates target the root document. - `GET /api/documents/{id}/download/`, `GET /api/documents/{id}/preview/`, `GET /api/documents/{id}/thumb/`, `GET /api/documents/{id}/metadata/`: accept `?version={version_id}`. - `POST /api/documents/{id}/update_version/`: uploads a new version using multipart form field `document` and optional `version_label`. +- `POST /api/documents/merge_as_versions/`: merges existing top-level documents as versions of a selected root. The JSON body must contain `documents` (at least two document IDs) and `root_document_id` (one of those IDs). When merging one source document, an optional `version_label` may be provided. - `PATCH /api/documents/{id}/versions/{version_id}/`: updates the `version_label` of a specific version. - `DELETE /api/documents/{root_id}/versions/{version_id}/`: deletes a non-root version. diff --git a/docs/usage.md b/docs/usage.md index 7fc245f22..8cc921b05 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -99,6 +99,10 @@ Think of versions as **file history** for a document. - By default, search and document content use the latest version. - In document detail, selecting a version switches the preview, file metadata and content (and download etc buttons) to that version. - Deleting a non-root version keeps metadata and falls back to the latest remaining version. +- From the document list, select two or more documents and choose **Merge as versions** to combine them under one entry. Select the root document whose metadata and permissions should be retained; the other selected documents become file versions. The root may already have versions, but documents being added as versions must not have version histories of their own. +- From a document's **Versions** menu, choose **Existing** to search for another document and add it as a version of the current document. +- Documents merged as versions give up their archive serial number. If the root has no ASN of its own it takes the first one, otherwise the ASNs are released and the removal is logged. +- Merging as versions cannot be undone from the UI, and deleting the root document moves its versions to the trash as well. ### Management Lists diff --git a/src-ui/src/app/components/common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component.html b/src-ui/src/app/components/common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component.html new file mode 100644 index 000000000..283a85bf1 --- /dev/null +++ b/src-ui/src/app/components/common/confirm-dialog/merge-as-versions-confirm-dialog/merge-as-versions-confirm-dialog.component.html @@ -0,0 +1,58 @@ +
{{message}}
+