mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	#186 allow filtering for documents with no correspondents / tags / types
This commit is contained in:
		| @@ -21,7 +21,7 @@ | |||||||
|       </div> |       </div> | ||||||
|       <div *ngIf="selectionModel.items" class="items"> |       <div *ngIf="selectionModel.items" class="items"> | ||||||
|         <ng-container *ngFor="let item of selectionModel.items | filter: filterText"> |         <ng-container *ngFor="let item of selectionModel.items | filter: filterText"> | ||||||
|           <app-toggleable-dropdown-button [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)"></app-toggleable-dropdown-button> |           <app-toggleable-dropdown-button *ngIf="allowSelectNone || item.id" [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)"></app-toggleable-dropdown-button> | ||||||
|         </ng-container> |         </ng-container> | ||||||
|       </div> |       </div> | ||||||
|       <button *ngIf="editing" class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!selectionModel.isDirty()"> |       <button *ngIf="editing" class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!selectionModel.isDirty()"> | ||||||
|   | |||||||
| @@ -53,6 +53,16 @@ export class FilterableDropdownSelectionModel { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (!id) { | ||||||
|  |       for (let key of this.temporarySelectionStates.keys()) { | ||||||
|  |         if (key) { | ||||||
|  |           this.temporarySelectionStates.delete(key) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       this.temporarySelectionStates.delete(null) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (fireEvent) { |     if (fireEvent) { | ||||||
|       this.changed.next(this) |       this.changed.next(this) | ||||||
|     } |     } | ||||||
| @@ -84,6 +94,10 @@ export class FilterableDropdownSelectionModel { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   isNoneSelected() { | ||||||
|  |     return this.selectionSize() == 1 && this.get(null) == ToggleableItemState.Selected | ||||||
|  |   } | ||||||
|  |  | ||||||
|   init(map) { |   init(map) { | ||||||
|     this.temporarySelectionStates = map |     this.temporarySelectionStates = map | ||||||
|     this.apply() |     this.apply() | ||||||
| @@ -126,7 +140,11 @@ export class FilterableDropdownComponent { | |||||||
|   @Input() |   @Input() | ||||||
|   set items(items: MatchingModel[]) { |   set items(items: MatchingModel[]) { | ||||||
|     if (items) { |     if (items) { | ||||||
|       this._selectionModel.items = items |       this._selectionModel.items = Array.from(items) | ||||||
|  |       this._selectionModel.items.unshift({ | ||||||
|  |         name: "None", | ||||||
|  |         id: null | ||||||
|  |       }) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -171,6 +189,9 @@ export class FilterableDropdownComponent { | |||||||
|   @Input() |   @Input() | ||||||
|   icon: string |   icon: string | ||||||
|  |  | ||||||
|  |   @Input() | ||||||
|  |   allowSelectNone: boolean = false | ||||||
|  |  | ||||||
|   @Input() |   @Input() | ||||||
|   editing = false |   editing = false | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,9 +8,9 @@ | |||||||
|   <div class="w-100 d-xl-none"></div> |   <div class="w-100 d-xl-none"></div> | ||||||
|    <div class="col col-xl-auto mb-2 mb-xl-0"> |    <div class="col col-xl-auto mb-2 mb-xl-0"> | ||||||
|      <div class="d-flex"> |      <div class="d-flex"> | ||||||
|        <app-filterable-dropdown class="mr-2 mr-md-3" [items]="tags" [(selectionModel)]="tagSelectionModel" (selectionModelChange)="updateRules()" [multiple]="true" title="Tags" icon="tag-fill" i18n-title></app-filterable-dropdown> |        <app-filterable-dropdown class="mr-2 mr-md-3" [items]="tags" [(selectionModel)]="tagSelectionModel" (selectionModelChange)="updateRules()" [multiple]="true" [allowSelectNone]="true" title="Tags" icon="tag-fill" i18n-title></app-filterable-dropdown> | ||||||
|        <app-filterable-dropdown class="mr-2 mr-md-3" [items]="correspondents" [(selectionModel)]="correspondentSelectionModel" (selectionModelChange)="updateRules()" title="Correspondents" icon="person-fill" i18n-title></app-filterable-dropdown> |        <app-filterable-dropdown class="mr-2 mr-md-3" [items]="correspondents" [(selectionModel)]="correspondentSelectionModel" (selectionModelChange)="updateRules()" [allowSelectNone]="true" title="Correspondents" icon="person-fill" i18n-title></app-filterable-dropdown> | ||||||
|        <app-filterable-dropdown class="mr-2 mr-md-3" [items]="documentTypes" [(selectionModel)]="documentTypeSelectionModel" (selectionModelChange)="updateRules()" title="Document types" icon="file-earmark-fill" i18n-title></app-filterable-dropdown> |        <app-filterable-dropdown class="mr-2 mr-md-3" [items]="documentTypes" [(selectionModel)]="documentTypeSelectionModel" (selectionModelChange)="updateRules()" [allowSelectNone]="true" title="Document types" icon="file-earmark-fill" i18n-title></app-filterable-dropdown> | ||||||
|        <app-date-dropdown class="mr-2 mr-md-3" [(dateBefore)]="dateCreatedBefore" [(dateAfter)]="dateCreatedAfter" title="Created" (datesSet)="updateRules()" i18n-title></app-date-dropdown> |        <app-date-dropdown class="mr-2 mr-md-3" [(dateBefore)]="dateCreatedBefore" [(dateAfter)]="dateCreatedAfter" title="Created" (datesSet)="updateRules()" i18n-title></app-date-dropdown> | ||||||
|        <app-date-dropdown [(dateBefore)]="dateAddedBefore" [(dateAfter)]="dateAddedAfter" title="Added"  (datesSet)="updateRules()" i18n-title></app-date-dropdown> |        <app-date-dropdown [(dateBefore)]="dateAddedBefore" [(dateAfter)]="dateAddedAfter" title="Added"  (datesSet)="updateRules()" i18n-title></app-date-dropdown> | ||||||
|      </div> |      </div> | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import { DocumentTypeService } from 'src/app/services/rest/document-type.service | |||||||
| import { TagService } from 'src/app/services/rest/tag.service'; | import { TagService } from 'src/app/services/rest/tag.service'; | ||||||
| import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; | import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; | ||||||
| import { FilterRule } from 'src/app/data/filter-rule'; | 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_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_TAG, FILTER_TITLE } from 'src/app/data/filter-rule-type'; | ||||||
| import { FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component'; | import { FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component'; | ||||||
| import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; | import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; | ||||||
|  |  | ||||||
| @@ -100,14 +100,18 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | |||||||
|     if (this._titleFilter) { |     if (this._titleFilter) { | ||||||
|       filterRules.push({rule_type: FILTER_TITLE, value: this._titleFilter}) |       filterRules.push({rule_type: FILTER_TITLE, value: this._titleFilter}) | ||||||
|     } |     } | ||||||
|     this.tagSelectionModel.getSelectedItems().forEach(tag => { |     if (this.tagSelectionModel.isNoneSelected()) { | ||||||
|       filterRules.push({rule_type: FILTER_HAS_TAG, value: tag.id.toString()}) |       filterRules.push({rule_type: FILTER_HAS_ANY_TAG, value: "false"}) | ||||||
|     }) |     } else { | ||||||
|  |       this.tagSelectionModel.getSelectedItems().filter(tag => tag.id).forEach(tag => { | ||||||
|  |         filterRules.push({rule_type: FILTER_HAS_TAG, value: tag.id?.toString()}) | ||||||
|  |       })   | ||||||
|  |     } | ||||||
|     this.correspondentSelectionModel.getSelectedItems().forEach(correspondent => { |     this.correspondentSelectionModel.getSelectedItems().forEach(correspondent => { | ||||||
|       filterRules.push({rule_type: FILTER_CORRESPONDENT, value: correspondent.id.toString()}) |       filterRules.push({rule_type: FILTER_CORRESPONDENT, value: correspondent.id?.toString()}) | ||||||
|     }) |     }) | ||||||
|     this.documentTypeSelectionModel.getSelectedItems().forEach(documentType => { |     this.documentTypeSelectionModel.getSelectedItems().forEach(documentType => { | ||||||
|       filterRules.push({rule_type: FILTER_DOCUMENT_TYPE, value: documentType.id.toString()}) |       filterRules.push({rule_type: FILTER_DOCUMENT_TYPE, value: documentType.id?.toString()}) | ||||||
|     }) |     }) | ||||||
|     if (this.dateCreatedBefore) { |     if (this.dateCreatedBefore) { | ||||||
|       filterRules.push({rule_type: FILTER_CREATED_BEFORE, value: this.dateCreatedBefore}) |       filterRules.push({rule_type: FILTER_CREATED_BEFORE, value: this.dateCreatedBefore}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 jonaswinkler
					jonaswinkler