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. diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf index 13deb8a89..11a735f25 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 «« - 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 « - 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 » - 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 »» - 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 First - 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 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/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 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/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 Last - 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 @@ -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 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 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() { 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( 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): """