From a93d83119eacbbc369964b6e3f13f8b5f79ab498 Mon Sep 17 00:00:00 2001
From: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 18 Nov 2025 04:55:39 +0000
Subject: [PATCH 1/7] Auto translate strings
---
src-ui/messages.xlf | 70 ++++++++++++++++++++++-----------------------
1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf
index 13deb8a89..c7c9ea4da 100644
--- a/src-ui/messages.xlf
+++ b/src-ui/messages.xlf
@@ -5,14 +5,14 @@
Close
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/alert/alert.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/alert/alert.ts
50
Slide of
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/carousel/carousel.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/carousel/carousel.ts
131,135
Currently selected slide number read by screen reader
@@ -20,212 +20,212 @@
Previous
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/carousel/carousel.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/carousel/carousel.ts
157,159
Next
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/carousel/carousel.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/carousel/carousel.ts
198
Previous month
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/datepicker/datepicker-navigation.ts
83,85
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/datepicker/datepicker-navigation.ts
112
Next month
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/datepicker/datepicker-navigation.ts
112
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/datepicker/datepicker-navigation.ts
112
HH
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Close
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Select month
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Hours
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
MM
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Select year
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Minutes
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Increment hours
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Decrement hours
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Increment minutes
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Decrement minutes
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
SS
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Seconds
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Increment seconds
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
Decrement seconds
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/ngb-config.ts
13
@@ -233,7 +233,7 @@
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/progressbar/progressbar.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.12_@angular+core@20.3.12_@angula_562237c7eed2d9c47098450f256dc04c/node_modules/src/progressbar/progressbar.ts
41,42
From 7a50157164cf710b57f20e58be5c730f0c52727b Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Tue, 18 Nov 2025 07:57:09 -0800
Subject: [PATCH 2/7] Fix: sort editing filterable dropdowns sooner (#11404)
---
.../filterable-dropdown.component.spec.ts | 41 +++++++++++++++++++
.../filterable-dropdown.component.ts | 23 ++++++++++-
2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts
index 5b643dc9f..2ecf95f2b 100644
--- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts
+++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts
@@ -631,6 +631,47 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
])
})
+ it('resorts items immediately when document count sorting enabled', () => {
+ const apple: Tag = { id: 55, name: 'Apple' }
+ const zebra: Tag = { id: 56, name: 'Zebra' }
+
+ selectionModel.documentCountSortingEnabled = true
+ selectionModel.items = [apple, zebra]
+ expect(selectionModel.items.map((item) => item?.id ?? null)).toEqual([
+ null,
+ apple.id,
+ zebra.id,
+ ])
+
+ selectionModel.documentCounts = [
+ { id: zebra.id, document_count: 5 },
+ { id: apple.id, document_count: 0 },
+ ]
+
+ expect(selectionModel.items.map((item) => item?.id ?? null)).toEqual([
+ null,
+ zebra.id,
+ apple.id,
+ ])
+ })
+
+ it('does not resort items by default when document counts are set', () => {
+ const first: Tag = { id: 57, name: 'First' }
+ const second: Tag = { id: 58, name: 'Second' }
+
+ selectionModel.items = [first, second]
+ selectionModel.documentCounts = [
+ { id: second.id, document_count: 10 },
+ { id: first.id, document_count: 0 },
+ ]
+
+ expect(selectionModel.items.map((item) => item?.id ?? null)).toEqual([
+ null,
+ first.id,
+ second.id,
+ ])
+ })
+
it('uses fallback document counts when selection data is missing', () => {
const fallbackRoot: Tag = {
id: 50,
diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
index 1e15930d1..ec5425630 100644
--- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
+++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
@@ -61,8 +61,13 @@ export class FilterableDropdownSelectionModel {
temporaryIntersection: Intersection = this._intersection
private _documentCounts: SelectionDataItem[] = []
+ public documentCountSortingEnabled = false
+
public set documentCounts(counts: SelectionDataItem[]) {
this._documentCounts = counts
+ if (this.documentCountSortingEnabled) {
+ this.sortItems()
+ }
}
private _items: MatchingModel[] = []
@@ -651,8 +656,9 @@ export class FilterableDropdownComponent
this.selectionModel.changed.complete()
model.items = this.selectionModel.items
model.manyToOne = this.selectionModel.manyToOne
- model.singleSelect = this.editing && !this.selectionModel.manyToOne
+ model.singleSelect = this._editing && !model.manyToOne
}
+ model.documentCountSortingEnabled = this._editing
model.changed.subscribe((updatedModel) => {
this.selectionModelChange.next(updatedModel)
})
@@ -682,8 +688,21 @@ export class FilterableDropdownComponent
@Input()
allowSelectNone: boolean = false
+ private _editing = false
+
@Input()
- editing = false
+ set editing(value: boolean) {
+ this._editing = value
+ if (this.selectionModel) {
+ this.selectionModel.singleSelect =
+ this._editing && !this.selectionModel.manyToOne
+ this.selectionModel.documentCountSortingEnabled = this._editing
+ }
+ }
+
+ get editing() {
+ return this._editing
+ }
@Input()
applyOnClose = false
From c05d75dab0568cd870561200d7880cef135c6f26 Mon Sep 17 00:00:00 2001
From: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 18 Nov 2025 15:58:50 +0000
Subject: [PATCH 3/7] Auto translate strings
---
src-ui/messages.xlf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf
index c7c9ea4da..11a735f25 100644
--- a/src-ui/messages.xlf
+++ b/src-ui/messages.xlf
@@ -5360,7 +5360,7 @@
Not assigned
src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
- 90
+ 95
Filter drop down element to filter for documents with no correspondent/type/tag assigned
@@ -5368,7 +5368,7 @@
Open filter
src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
- 748
+ 767
From 4bf681387a6701d252188f66c70a550109abfe5a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 18 Nov 2025 09:29:39 -0800
Subject: [PATCH 4/7] docker-compose(deps): bump gotenberg/gotenberg in
/docker/compose (#11393)
Bumps gotenberg/gotenberg from 8.24 to 8.25.
---
updated-dependencies:
- dependency-name: gotenberg/gotenberg
dependency-version: '8.25'
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
docker/compose/docker-compose.ci-test.yml | 2 +-
docker/compose/docker-compose.mariadb-tika.yml | 2 +-
docker/compose/docker-compose.postgres-tika.yml | 2 +-
docker/compose/docker-compose.sqlite-tika.yml | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/docker/compose/docker-compose.ci-test.yml b/docker/compose/docker-compose.ci-test.yml
index 701d323c7..d277406b8 100644
--- a/docker/compose/docker-compose.ci-test.yml
+++ b/docker/compose/docker-compose.ci-test.yml
@@ -4,7 +4,7 @@
# correct networking for the tests
services:
gotenberg:
- image: docker.io/gotenberg/gotenberg:8.24
+ image: docker.io/gotenberg/gotenberg:8.25
hostname: gotenberg
container_name: gotenberg
network_mode: host
diff --git a/docker/compose/docker-compose.mariadb-tika.yml b/docker/compose/docker-compose.mariadb-tika.yml
index c2b625188..03601e63e 100644
--- a/docker/compose/docker-compose.mariadb-tika.yml
+++ b/docker/compose/docker-compose.mariadb-tika.yml
@@ -72,7 +72,7 @@ services:
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
- image: docker.io/gotenberg/gotenberg:8.24
+ image: docker.io/gotenberg/gotenberg:8.25
restart: unless-stopped
# The gotenberg chromium route is used to convert .eml files. We do not
# want to allow external content like tracking pixels or even javascript.
diff --git a/docker/compose/docker-compose.postgres-tika.yml b/docker/compose/docker-compose.postgres-tika.yml
index 530212b51..19a164025 100644
--- a/docker/compose/docker-compose.postgres-tika.yml
+++ b/docker/compose/docker-compose.postgres-tika.yml
@@ -66,7 +66,7 @@ services:
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
- image: docker.io/gotenberg/gotenberg:8.24
+ image: docker.io/gotenberg/gotenberg:8.25
restart: unless-stopped
# The gotenberg chromium route is used to convert .eml files. We do not
# want to allow external content like tracking pixels or even javascript.
diff --git a/docker/compose/docker-compose.sqlite-tika.yml b/docker/compose/docker-compose.sqlite-tika.yml
index b849a8ed3..598328907 100644
--- a/docker/compose/docker-compose.sqlite-tika.yml
+++ b/docker/compose/docker-compose.sqlite-tika.yml
@@ -55,7 +55,7 @@ services:
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
- image: docker.io/gotenberg/gotenberg:8.24
+ image: docker.io/gotenberg/gotenberg:8.25
restart: unless-stopped
# The gotenberg chromium route is used to convert .eml files. We do not
# want to allow external content like tracking pixels or even javascript.
From 36d45ecf4d68502abd494053ac13ae44226f185a Mon Sep 17 00:00:00 2001
From: Ed Bardsley
Date: Tue, 18 Nov 2025 10:28:43 -0800
Subject: [PATCH 5/7] Development: fix unreachable code around assertRaises
blocks (#11365)
* tests: general cleanup and fixes for runnning under docker
This now allows tests to be run under a locally built or production
docker image with something like:
`docker run --rm -v $PWD:/usr/src/paperless --entrypoint=bash paperlessngx/paperless-ngx:latest -c "uv run pytest"`
Specific fixes:
- fix unreachable code around `assertRaises` blocks
- fix `assertInt` typos
- fix `str(e)` vs `str(e.exception)` issues
- skip permission-based checks when root (in a docker container)
- catch `OSError` problems when instantiating `INotify` and
skip inotify-based tests when it's unavailable.
* Reverts most files to dev while keeping the exception assert fixes
---------
Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
---
.../tests/test_management_exporter.py | 9 +++--
src/documents/tests/test_management_fuzzy.py | 6 ++--
.../tests/test_management_importer.py | 35 +++++++++----------
3 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/src/documents/tests/test_management_exporter.py b/src/documents/tests/test_management_exporter.py
index a67e5e8c5..b01b8d47e 100644
--- a/src/documents/tests/test_management_exporter.py
+++ b/src/documents/tests/test_management_exporter.py
@@ -571,7 +571,7 @@ class TestExportImport(
with self.assertRaises(CommandError) as e:
call_command(*args)
- self.assertEqual("That path isn't a directory", str(e))
+ self.assertEqual("That path doesn't exist", str(e.exception))
def test_export_target_exists_but_is_file(self):
"""
@@ -589,7 +589,7 @@ class TestExportImport(
with self.assertRaises(CommandError) as e:
call_command(*args)
- self.assertEqual("That path isn't a directory", str(e))
+ self.assertEqual("That path isn't a directory", str(e.exception))
def test_export_target_not_writable(self):
"""
@@ -608,7 +608,10 @@ class TestExportImport(
with self.assertRaises(CommandError) as e:
call_command(*args)
- self.assertEqual("That path doesn't appear to be writable", str(e))
+ self.assertEqual(
+ "That path doesn't appear to be writable",
+ str(e.exception),
+ )
def test_no_archive(self):
"""
diff --git a/src/documents/tests/test_management_fuzzy.py b/src/documents/tests/test_management_fuzzy.py
index 453a86082..2a4f28025 100644
--- a/src/documents/tests/test_management_fuzzy.py
+++ b/src/documents/tests/test_management_fuzzy.py
@@ -34,7 +34,7 @@ class TestFuzzyMatchCommand(TestCase):
"""
with self.assertRaises(CommandError) as e:
self.call_command("--ratio", "-1")
- self.assertIn("The ratio must be between 0 and 100", str(e))
+ self.assertIn("The ratio must be between 0 and 100", str(e.exception))
def test_invalid_ratio_upper_limit(self):
"""
@@ -47,7 +47,7 @@ class TestFuzzyMatchCommand(TestCase):
"""
with self.assertRaises(CommandError) as e:
self.call_command("--ratio", "101")
- self.assertIn("The ratio must be between 0 and 100", str(e))
+ self.assertIn("The ratio must be between 0 and 100", str(e.exception))
def test_invalid_process_count(self):
"""
@@ -60,7 +60,7 @@ class TestFuzzyMatchCommand(TestCase):
"""
with self.assertRaises(CommandError) as e:
self.call_command("--processes", "0")
- self.assertIn("There must be at least 1 process", str(e))
+ self.assertIn("There must be at least 1 process", str(e.exception))
def test_no_matches(self):
"""
diff --git a/src/documents/tests/test_management_importer.py b/src/documents/tests/test_management_importer.py
index e700ecdc9..004f5ac5f 100644
--- a/src/documents/tests/test_management_importer.py
+++ b/src/documents/tests/test_management_importer.py
@@ -40,10 +40,10 @@ class TestCommandImport(
"--no-progress-bar",
str(self.dirs.scratch_dir),
)
- self.assertIn(
- "That directory doesn't appear to contain a manifest.json file.",
- str(e),
- )
+ self.assertIn(
+ "That directory doesn't appear to contain a manifest.json file.",
+ str(e.exception),
+ )
def test_check_manifest_malformed(self):
"""
@@ -66,10 +66,10 @@ class TestCommandImport(
"--no-progress-bar",
str(self.dirs.scratch_dir),
)
- self.assertIn(
- "The manifest file contains a record which does not refer to an actual document file.",
- str(e),
- )
+ self.assertIn(
+ "The manifest file contains a record which does not refer to an actual document file.",
+ str(e.exception),
+ )
def test_check_manifest_file_not_found(self):
"""
@@ -95,7 +95,7 @@ class TestCommandImport(
"--no-progress-bar",
str(self.dirs.scratch_dir),
)
- self.assertIn('The manifest file refers to "noexist.pdf"', str(e))
+ self.assertIn('The manifest file refers to "noexist.pdf"', str(e.exception))
def test_import_permission_error(self):
"""
@@ -129,14 +129,14 @@ class TestCommandImport(
cmd.data_only = False
with self.assertRaises(CommandError) as cm:
cmd.check_manifest_validity()
- self.assertInt("Failed to read from original file", str(cm.exception))
+ self.assertIn("Failed to read from original file", str(cm.exception))
original_path.chmod(0o444)
archive_path.chmod(0o222)
with self.assertRaises(CommandError) as cm:
cmd.check_manifest_validity()
- self.assertInt("Failed to read from archive file", str(cm.exception))
+ self.assertIn("Failed to read from archive file", str(cm.exception))
def test_import_source_not_existing(self):
"""
@@ -149,7 +149,7 @@ class TestCommandImport(
"""
with self.assertRaises(CommandError) as cm:
call_command("document_importer", Path("/tmp/notapath"))
- self.assertInt("That path doesn't exist", str(cm.exception))
+ self.assertIn("That path doesn't exist", str(cm.exception))
def test_import_source_not_readable(self):
"""
@@ -165,10 +165,10 @@ class TestCommandImport(
path.chmod(0o222)
with self.assertRaises(CommandError) as cm:
call_command("document_importer", path)
- self.assertInt(
- "That path doesn't appear to be readable",
- str(cm.exception),
- )
+ self.assertIn(
+ "That path doesn't appear to be readable",
+ str(cm.exception),
+ )
def test_import_source_does_not_exist(self):
"""
@@ -185,8 +185,7 @@ class TestCommandImport(
with self.assertRaises(CommandError) as e:
call_command("document_importer", "--no-progress-bar", str(path))
-
- self.assertIn("That path doesn't exist", str(e))
+ self.assertIn("That path doesn't exist", str(e.exception))
def test_import_files_exist(self):
"""
From 7b175ec1b37008a66ec7dfe35c3ae91e4507bda2 Mon Sep 17 00:00:00 2001
From: david-loe <56305409+david-loe@users.noreply.github.com>
Date: Tue, 18 Nov 2025 20:28:52 +0100
Subject: [PATCH 6/7] Development: fix correct test delete select option
(#11406)
---
src/documents/tests/test_api_custom_fields.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/documents/tests/test_api_custom_fields.py b/src/documents/tests/test_api_custom_fields.py
index 8e24226dc..31dd14b88 100644
--- a/src/documents/tests/test_api_custom_fields.py
+++ b/src/documents/tests/test_api_custom_fields.py
@@ -242,7 +242,7 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
CustomFieldInstance.objects.create(
document=doc,
field=custom_field_select,
- value_text="abc-123",
+ value_select="def-456",
)
resp = self.client.patch(
From 80be6793cf5c52add874ea711f99b4cff835686f Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Tue, 18 Nov 2025 12:05:48 -0800
Subject: [PATCH 7/7] Fix: prevent focus loss from change detection in cf query
dropdown (#11409)
---
.../filter-editor/filter-editor.component.ts | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts
index fecbaa170..9ffcc380b 100644
--- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts
+++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts
@@ -400,6 +400,9 @@ export class FilterEditorComponent
@Input()
set filterRules(value: FilterRule[]) {
+ if (value === this._filterRules) {
+ return
+ }
this._filterRules = value
this.documentTypeSelectionModel.clear(false)
@@ -1098,7 +1101,13 @@ export class FilterEditorComponent
rulesModified: boolean = false
updateRules() {
- this.filterRulesChange.next(this.filterRules)
+ const updatedRules = this.filterRules
+ this._filterRules = updatedRules
+ this.rulesModified = filterRulesDiffer(
+ this._unmodifiedFilterRules,
+ updatedRules
+ )
+ this.filterRulesChange.next(updatedRules)
}
get textFilter() {