mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Add support for 'any' ('OR') of tags when filtering
This commit is contained in:
		| @@ -12,6 +12,16 @@ | ||||
|   </button> | ||||
|   <div class="dropdown-menu py-0 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}"> | ||||
|     <div class="list-group list-group-flush"> | ||||
|       <div *ngIf="!editing && multiple" class="list-group-item d-flex"> | ||||
|         <div class="btn-group btn-group-xs btn-group-toggle flex-fill" ngbRadioGroup [(ngModel)]="selectionModel.logicalOperator"> | ||||
|           <label ngbButtonLabel class="btn btn-outline-primary"> | ||||
|             <input ngbButton type="radio" name="logicalOperator" value="and"> All | ||||
|           </label> | ||||
|           <label ngbButtonLabel class="btn btn-outline-primary"> | ||||
|             <input ngbButton type="radio" name="logicalOperator" value="or"> Any | ||||
|           </label> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="list-group-item"> | ||||
|         <div class="input-group input-group-sm"> | ||||
|           <input class="form-control" type="text" [(ngModel)]="filterText" [placeholder]="filterPlaceholder" (keyup.enter)="listFilterEnter()" #listFilterTextInput> | ||||
|   | ||||
| @@ -12,3 +12,22 @@ | ||||
|     overflow-y: scroll; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .btn-group-xs { | ||||
|   > .btn { | ||||
|     padding: 0.2rem 0.25rem; | ||||
|     font-size: 0.675rem; | ||||
|     line-height: 1.2; | ||||
|     border-radius: 0.15rem; | ||||
|   } | ||||
|  | ||||
|   > .btn:not(:first-child) { | ||||
|     border-top-left-radius: 0; | ||||
|     border-bottom-left-radius: 0; | ||||
|   } | ||||
|  | ||||
|   > .btn:not(:last-child) { | ||||
|     border-top-right-radius: 0; | ||||
|     border-bottom-right-radius: 0; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ export class FilterableDropdownSelectionModel { | ||||
|   changed = new Subject<FilterableDropdownSelectionModel>() | ||||
|  | ||||
|   multiple = false | ||||
|   logicalOperator = 'and' | ||||
|  | ||||
|   items: MatchingModel[] = [] | ||||
|  | ||||
| @@ -83,7 +84,7 @@ export class FilterableDropdownSelectionModel { | ||||
|     if (fireEvent) { | ||||
|       this.changed.next(this) | ||||
|     } | ||||
|      | ||||
|  | ||||
|   } | ||||
|  | ||||
|   private getNonTemporary(id: number) { | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import { DocumentTypeService } from 'src/app/services/rest/document-type.service | ||||
| import { TagService } from 'src/app/services/rest/tag.service'; | ||||
| import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; | ||||
| import { FilterRule } from 'src/app/data/filter-rule'; | ||||
| import { FILTER_ADDED_AFTER, FILTER_ADDED_BEFORE, FILTER_CORRESPONDENT, FILTER_CREATED_AFTER, FILTER_CREATED_BEFORE, FILTER_DOCUMENT_TYPE, FILTER_HAS_ANY_TAG, FILTER_HAS_TAG, FILTER_TITLE } from 'src/app/data/filter-rule-type'; | ||||
| import { FILTER_ADDED_AFTER, FILTER_ADDED_BEFORE, FILTER_CORRESPONDENT, FILTER_CREATED_AFTER, FILTER_CREATED_BEFORE, FILTER_DOCUMENT_TYPE, FILTER_HAS_ANY_TAG, FILTER_HAS_TAGS_ALL, FILTER_HAS_TAGS_ANY, FILTER_TITLE } from 'src/app/data/filter-rule-type'; | ||||
| import { FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component'; | ||||
| import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; | ||||
|  | ||||
| @@ -38,7 +38,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|             return $localize`Without document type` | ||||
|           } | ||||
|  | ||||
|         case FILTER_HAS_TAG: | ||||
|         case FILTER_HAS_TAGS_ALL: | ||||
|           return $localize`Tag: ${this.tags.find(t => t.id == +rule.value)?.name}` | ||||
|  | ||||
|         case FILTER_HAS_ANY_TAG: | ||||
| @@ -101,7 +101,11 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|         case FILTER_ADDED_BEFORE: | ||||
|           this.dateAddedBefore = rule.value | ||||
|           break | ||||
|         case FILTER_HAS_TAG: | ||||
|         case FILTER_HAS_TAGS_ALL: | ||||
|           this.tagSelectionModel.set(rule.value ? +rule.value : null, ToggleableItemState.Selected, false) | ||||
|           break | ||||
|         case FILTER_HAS_TAGS_ANY: | ||||
|           this.tagSelectionModel.logicalOperator = 'or' | ||||
|           this.tagSelectionModel.set(rule.value ? +rule.value : null, ToggleableItemState.Selected, false) | ||||
|           break | ||||
|         case FILTER_HAS_ANY_TAG: | ||||
| @@ -125,8 +129,9 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|     if (this.tagSelectionModel.isNoneSelected()) { | ||||
|       filterRules.push({rule_type: FILTER_HAS_ANY_TAG, value: "false"}) | ||||
|     } else { | ||||
|       const tagFilterType = this.tagSelectionModel.logicalOperator == 'and' ? FILTER_HAS_TAGS_ALL : FILTER_HAS_TAGS_ANY | ||||
|       this.tagSelectionModel.getSelectedItems().filter(tag => tag.id).forEach(tag => { | ||||
|         filterRules.push({rule_type: FILTER_HAS_TAG, value: tag.id?.toString()}) | ||||
|         filterRules.push({rule_type: tagFilterType, value: tag.id?.toString()}) | ||||
|       }) | ||||
|     } | ||||
|     this.correspondentSelectionModel.getSelectedItems().forEach(correspondent => { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { Component } from '@angular/core'; | ||||
| import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; | ||||
| import { FILTER_HAS_TAG } from 'src/app/data/filter-rule-type'; | ||||
| import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type'; | ||||
| import { TAG_COLOURS, PaperlessTag } from 'src/app/data/paperless-tag'; | ||||
| import { DocumentListViewService } from 'src/app/services/document-list-view.service'; | ||||
| import { TagService } from 'src/app/services/rest/tag.service'; | ||||
| @@ -31,7 +31,7 @@ export class TagListComponent extends GenericListComponent<PaperlessTag> { | ||||
|   } | ||||
|  | ||||
|   filterDocuments(object: PaperlessTag) { | ||||
|     this.list.quickFilter([{rule_type: FILTER_HAS_TAG, value: object.id.toString()}]) | ||||
|     this.list.quickFilter([{rule_type: FILTER_HAS_TAGS_ALL, value: object.id.toString()}]) | ||||
|  | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,8 +4,9 @@ export const FILTER_ASN = 2 | ||||
| export const FILTER_CORRESPONDENT = 3 | ||||
| export const FILTER_DOCUMENT_TYPE = 4 | ||||
| export const FILTER_IS_IN_INBOX = 5 | ||||
| export const FILTER_HAS_TAG = 6 | ||||
| export const FILTER_HAS_TAGS_ALL = 6 | ||||
| export const FILTER_HAS_ANY_TAG = 7 | ||||
| export const FILTER_HAS_TAGS_ANY = 19 | ||||
| export const FILTER_CREATED_BEFORE = 8 | ||||
| export const FILTER_CREATED_AFTER = 9 | ||||
| export const FILTER_CREATED_YEAR = 10 | ||||
| @@ -31,7 +32,8 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|   {id: FILTER_DOCUMENT_TYPE, filtervar: "document_type__id", isnull_filtervar: "document_type__isnull", datatype: "document_type", multi: false}, | ||||
|  | ||||
|   {id: FILTER_IS_IN_INBOX, filtervar: "is_in_inbox", datatype: "boolean", multi: false, default: true}, | ||||
|   {id: FILTER_HAS_TAG, filtervar: "tags__id__all", datatype: "tag", multi: true}, | ||||
|   {id: FILTER_HAS_TAGS_ALL, filtervar: "tags__id__all", datatype: "tag", multi: true}, | ||||
|   {id: FILTER_HAS_TAGS_ANY, filtervar: "tags__id__in", datatype: "tag", multi: true}, | ||||
|   {id: FILTER_DOES_NOT_HAVE_TAG, filtervar: "tags__id__none", datatype: "tag", multi: true}, | ||||
|   {id: FILTER_HAS_ANY_TAG, filtervar: "is_tagged", datatype: "boolean", multi: false, default: true}, | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Michael Shamoon
					Michael Shamoon