mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Merge pull request #920 from paperless-ngx/frontend-asn-empty
Feature: allow all ASN filtering functions
This commit is contained in:
		| @@ -8,7 +8,10 @@ | |||||||
|               <button *ngFor="let t of textFilterTargets" ngbDropdownItem [class.active]="textFilterTarget == t.id" (click)="changeTextFilterTarget(t.id)">{{t.name}}</button> |               <button *ngFor="let t of textFilterTargets" ngbDropdownItem [class.active]="textFilterTarget == t.id" (click)="changeTextFilterTarget(t.id)">{{t.name}}</button> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|           <input #textFilterInput class="form-control form-control-sm" type="text" [(ngModel)]="textFilter" (keyup.enter)="textFilterEnter()" [readonly]="textFilterTarget == 'fulltext-morelike'"> |           <select *ngIf="textFilterTarget == 'asn'" class="form-select flex-grow-0 w-auto" [(ngModel)]="textFilterModifier" (change)="textFilterModifierChange()"> | ||||||
|  |             <option *ngFor="let m of textFilterModifiers" ngbDropdownItem [value]="m.id">{{m.label}}</option> | ||||||
|  |           </select> | ||||||
|  |           <input #textFilterInput class="form-control form-control-sm" type="text" [disabled]="textFilterModifierIsNull" [(ngModel)]="textFilter" (keyup.enter)="textFilterEnter()" [readonly]="textFilterTarget == 'fulltext-morelike'"> | ||||||
|          </div> |          </div> | ||||||
|      </div> |      </div> | ||||||
|   </div> |   </div> | ||||||
|   | |||||||
| @@ -33,6 +33,9 @@ import { | |||||||
|   FILTER_DOES_NOT_HAVE_TAG, |   FILTER_DOES_NOT_HAVE_TAG, | ||||||
|   FILTER_TITLE, |   FILTER_TITLE, | ||||||
|   FILTER_TITLE_CONTENT, |   FILTER_TITLE_CONTENT, | ||||||
|  |   FILTER_ASN_ISNULL, | ||||||
|  |   FILTER_ASN_GT, | ||||||
|  |   FILTER_ASN_LT, | ||||||
| } from 'src/app/data/filter-rule-type' | } 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' | ||||||
| @@ -45,6 +48,12 @@ const TEXT_FILTER_TARGET_ASN = 'asn' | |||||||
| const TEXT_FILTER_TARGET_FULLTEXT_QUERY = 'fulltext-query' | const TEXT_FILTER_TARGET_FULLTEXT_QUERY = 'fulltext-query' | ||||||
| const TEXT_FILTER_TARGET_FULLTEXT_MORELIKE = 'fulltext-morelike' | const TEXT_FILTER_TARGET_FULLTEXT_MORELIKE = 'fulltext-morelike' | ||||||
|  |  | ||||||
|  | const TEXT_FILTER_MODIFIER_EQUALS = 'equals' | ||||||
|  | const TEXT_FILTER_MODIFIER_NULL = 'is null' | ||||||
|  | const TEXT_FILTER_MODIFIER_NOTNULL = 'not null' | ||||||
|  | const TEXT_FILTER_MODIFIER_GT = 'greater' | ||||||
|  | const TEXT_FILTER_MODIFIER_LT = 'less' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-filter-editor', |   selector: 'app-filter-editor', | ||||||
|   templateUrl: './filter-editor.component.html', |   templateUrl: './filter-editor.component.html', | ||||||
| @@ -141,6 +150,39 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | |||||||
|       ?.name |       ?.name | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public textFilterModifier: string | ||||||
|  |  | ||||||
|  |   get textFilterModifiers() { | ||||||
|  |     return [ | ||||||
|  |       { | ||||||
|  |         id: TEXT_FILTER_MODIFIER_EQUALS, | ||||||
|  |         label: $localize`equals`, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         id: TEXT_FILTER_MODIFIER_NULL, | ||||||
|  |         label: $localize`is empty`, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         id: TEXT_FILTER_MODIFIER_NOTNULL, | ||||||
|  |         label: $localize`is not empty`, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         id: TEXT_FILTER_MODIFIER_GT, | ||||||
|  |         label: $localize`greater than`, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         id: TEXT_FILTER_MODIFIER_LT, | ||||||
|  |         label: $localize`less than`, | ||||||
|  |       }, | ||||||
|  |     ] | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   get textFilterModifierIsNull(): boolean { | ||||||
|  |     return [TEXT_FILTER_MODIFIER_NULL, TEXT_FILTER_MODIFIER_NOTNULL].includes( | ||||||
|  |       this.textFilterModifier | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   tagSelectionModel = new FilterableDropdownSelectionModel() |   tagSelectionModel = new FilterableDropdownSelectionModel() | ||||||
|   correspondentSelectionModel = new FilterableDropdownSelectionModel() |   correspondentSelectionModel = new FilterableDropdownSelectionModel() | ||||||
|   documentTypeSelectionModel = new FilterableDropdownSelectionModel() |   documentTypeSelectionModel = new FilterableDropdownSelectionModel() | ||||||
| @@ -176,6 +218,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | |||||||
|     this.dateAddedAfter = null |     this.dateAddedAfter = null | ||||||
|     this.dateCreatedBefore = null |     this.dateCreatedBefore = null | ||||||
|     this.dateCreatedAfter = null |     this.dateCreatedAfter = null | ||||||
|  |     this.textFilterModifier = TEXT_FILTER_MODIFIER_EQUALS | ||||||
|  |  | ||||||
|     value.forEach((rule) => { |     value.forEach((rule) => { | ||||||
|       switch (rule.rule_type) { |       switch (rule.rule_type) { | ||||||
| @@ -254,6 +297,20 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | |||||||
|             false |             false | ||||||
|           ) |           ) | ||||||
|           break |           break | ||||||
|  |         case FILTER_ASN_ISNULL: | ||||||
|  |           this.textFilterTarget = TEXT_FILTER_TARGET_ASN | ||||||
|  |           this.textFilterModifier = TEXT_FILTER_MODIFIER_NULL | ||||||
|  |           break | ||||||
|  |         case FILTER_ASN_GT: | ||||||
|  |           this.textFilterTarget = TEXT_FILTER_TARGET_ASN | ||||||
|  |           this.textFilterModifier = TEXT_FILTER_MODIFIER_GT | ||||||
|  |           this._textFilter = rule.value | ||||||
|  |           break | ||||||
|  |         case FILTER_ASN_LT: | ||||||
|  |           this.textFilterTarget = TEXT_FILTER_TARGET_ASN | ||||||
|  |           this.textFilterModifier = TEXT_FILTER_MODIFIER_LT | ||||||
|  |           this._textFilter = rule.value | ||||||
|  |           break | ||||||
|       } |       } | ||||||
|     }) |     }) | ||||||
|     this.checkIfRulesHaveChanged() |     this.checkIfRulesHaveChanged() | ||||||
| @@ -273,8 +330,33 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | |||||||
|     if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_TITLE) { |     if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_TITLE) { | ||||||
|       filterRules.push({ rule_type: FILTER_TITLE, value: this._textFilter }) |       filterRules.push({ rule_type: FILTER_TITLE, value: this._textFilter }) | ||||||
|     } |     } | ||||||
|     if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_ASN) { |     if (this.textFilterTarget == TEXT_FILTER_TARGET_ASN) { | ||||||
|  |       if ( | ||||||
|  |         this.textFilterModifier == TEXT_FILTER_MODIFIER_EQUALS && | ||||||
|  |         this._textFilter | ||||||
|  |       ) { | ||||||
|         filterRules.push({ rule_type: FILTER_ASN, value: this._textFilter }) |         filterRules.push({ rule_type: FILTER_ASN, value: this._textFilter }) | ||||||
|  |       } else if (this.textFilterModifierIsNull) { | ||||||
|  |         filterRules.push({ | ||||||
|  |           rule_type: FILTER_ASN_ISNULL, | ||||||
|  |           value: ( | ||||||
|  |             this.textFilterModifier == TEXT_FILTER_MODIFIER_NULL | ||||||
|  |           ).toString(), | ||||||
|  |         }) | ||||||
|  |       } else if ( | ||||||
|  |         [TEXT_FILTER_MODIFIER_GT, TEXT_FILTER_MODIFIER_LT].includes( | ||||||
|  |           this.textFilterModifier | ||||||
|  |         ) && | ||||||
|  |         this._textFilter | ||||||
|  |       ) { | ||||||
|  |         filterRules.push({ | ||||||
|  |           rule_type: | ||||||
|  |             this.textFilterModifier == TEXT_FILTER_MODIFIER_GT | ||||||
|  |               ? FILTER_ASN_GT | ||||||
|  |               : FILTER_ASN_LT, | ||||||
|  |           value: this._textFilter, | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|     if ( |     if ( | ||||||
|       this._textFilter && |       this._textFilter && | ||||||
| @@ -398,7 +480,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   get textFilter() { |   get textFilter() { | ||||||
|     return this._textFilter |     return this.textFilterModifierIsNull ? '' : this._textFilter | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   set textFilter(value) { |   set textFilter(value) { | ||||||
| @@ -498,4 +580,18 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | |||||||
|     this.textFilterInput.nativeElement.focus() |     this.textFilterInput.nativeElement.focus() | ||||||
|     this.updateRules() |     this.updateRules() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   textFilterModifierChange() { | ||||||
|  |     if ( | ||||||
|  |       this.textFilterModifierIsNull || | ||||||
|  |       ([ | ||||||
|  |         TEXT_FILTER_MODIFIER_EQUALS, | ||||||
|  |         TEXT_FILTER_MODIFIER_GT, | ||||||
|  |         TEXT_FILTER_MODIFIER_LT, | ||||||
|  |       ].includes(this.textFilterModifier) && | ||||||
|  |         this._textFilter) | ||||||
|  |     ) { | ||||||
|  |       this.updateRules() | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,11 +20,13 @@ export const FILTER_MODIFIED_AFTER = 16 | |||||||
| export const FILTER_DOES_NOT_HAVE_TAG = 17 | export const FILTER_DOES_NOT_HAVE_TAG = 17 | ||||||
|  |  | ||||||
| export const FILTER_ASN_ISNULL = 18 | export const FILTER_ASN_ISNULL = 18 | ||||||
|  | export const FILTER_ASN_GT = 19 | ||||||
|  | export const FILTER_ASN_LT = 20 | ||||||
|  |  | ||||||
| export const FILTER_TITLE_CONTENT = 19 | export const FILTER_TITLE_CONTENT = 21 | ||||||
|  |  | ||||||
| export const FILTER_FULLTEXT_QUERY = 20 | export const FILTER_FULLTEXT_QUERY = 22 | ||||||
| export const FILTER_FULLTEXT_MORELIKE = 21 | export const FILTER_FULLTEXT_MORELIKE = 23 | ||||||
|  |  | ||||||
| export const FILTER_RULE_TYPES: FilterRuleType[] = [ | export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||||
|   { |   { | ||||||
| @@ -41,14 +43,12 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | |||||||
|     multi: false, |     multi: false, | ||||||
|     default: '', |     default: '', | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   { |   { | ||||||
|     id: FILTER_ASN, |     id: FILTER_ASN, | ||||||
|     filtervar: 'archive_serial_number', |     filtervar: 'archive_serial_number', | ||||||
|     datatype: 'number', |     datatype: 'number', | ||||||
|     multi: false, |     multi: false, | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   { |   { | ||||||
|     id: FILTER_CORRESPONDENT, |     id: FILTER_CORRESPONDENT, | ||||||
|     filtervar: 'correspondent__id', |     filtervar: 'correspondent__id', | ||||||
| @@ -63,7 +63,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | |||||||
|     datatype: 'document_type', |     datatype: 'document_type', | ||||||
|     multi: false, |     multi: false, | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   { |   { | ||||||
|     id: FILTER_IS_IN_INBOX, |     id: FILTER_IS_IN_INBOX, | ||||||
|     filtervar: 'is_in_inbox', |     filtervar: 'is_in_inbox', | ||||||
| @@ -96,7 +95,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | |||||||
|     multi: false, |     multi: false, | ||||||
|     default: true, |     default: true, | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   { |   { | ||||||
|     id: FILTER_CREATED_BEFORE, |     id: FILTER_CREATED_BEFORE, | ||||||
|     filtervar: 'created__date__lt', |     filtervar: 'created__date__lt', | ||||||
| @@ -109,7 +107,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | |||||||
|     datatype: 'date', |     datatype: 'date', | ||||||
|     multi: false, |     multi: false, | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   { |   { | ||||||
|     id: FILTER_CREATED_YEAR, |     id: FILTER_CREATED_YEAR, | ||||||
|     filtervar: 'created__year', |     filtervar: 'created__year', | ||||||
| @@ -141,7 +138,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | |||||||
|     datatype: 'date', |     datatype: 'date', | ||||||
|     multi: false, |     multi: false, | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   { |   { | ||||||
|     id: FILTER_MODIFIED_BEFORE, |     id: FILTER_MODIFIED_BEFORE, | ||||||
|     filtervar: 'modified__date__lt', |     filtervar: 'modified__date__lt', | ||||||
| @@ -160,14 +156,24 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | |||||||
|     datatype: 'boolean', |     datatype: 'boolean', | ||||||
|     multi: false, |     multi: false, | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     id: FILTER_ASN_GT, | ||||||
|  |     filtervar: 'archive_serial_number__gt', | ||||||
|  |     datatype: 'number', | ||||||
|  |     multi: false, | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     id: FILTER_ASN_LT, | ||||||
|  |     filtervar: 'archive_serial_number__lt', | ||||||
|  |     datatype: 'number', | ||||||
|  |     multi: false, | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     id: FILTER_TITLE_CONTENT, |     id: FILTER_TITLE_CONTENT, | ||||||
|     filtervar: 'title_content', |     filtervar: 'title_content', | ||||||
|     datatype: 'string', |     datatype: 'string', | ||||||
|     multi: false, |     multi: false, | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   { |   { | ||||||
|     id: FILTER_FULLTEXT_QUERY, |     id: FILTER_FULLTEXT_QUERY, | ||||||
|     filtervar: 'query', |     filtervar: 'query', | ||||||
|   | |||||||
| @@ -261,6 +261,11 @@ textarea, | |||||||
|   border-color: var(--bs-primary); |   border-color: var(--bs-primary); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .form-control:disabled, .form-control[readonly] { | ||||||
|  |   background-color: var(--pngx-bg-alt); | ||||||
|  |   cursor: not-allowed; | ||||||
|  | } | ||||||
|  |  | ||||||
| .page-link { | .page-link { | ||||||
|   color: var(--bs-secondary); |   color: var(--bs-secondary); | ||||||
|   background-color: var(--bs-body-bg); |   background-color: var(--bs-body-bg); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Quinn Casey
					Quinn Casey