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> | ||||
|             </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> | ||||
|   | ||||
| @@ -33,6 +33,9 @@ import { | ||||
|   FILTER_DOES_NOT_HAVE_TAG, | ||||
|   FILTER_TITLE, | ||||
|   FILTER_TITLE_CONTENT, | ||||
|   FILTER_ASN_ISNULL, | ||||
|   FILTER_ASN_GT, | ||||
|   FILTER_ASN_LT, | ||||
| } 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' | ||||
| @@ -45,6 +48,12 @@ const TEXT_FILTER_TARGET_ASN = 'asn' | ||||
| const TEXT_FILTER_TARGET_FULLTEXT_QUERY = 'fulltext-query' | ||||
| 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({ | ||||
|   selector: 'app-filter-editor', | ||||
|   templateUrl: './filter-editor.component.html', | ||||
| @@ -141,6 +150,39 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|       ?.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() | ||||
|   correspondentSelectionModel = new FilterableDropdownSelectionModel() | ||||
|   documentTypeSelectionModel = new FilterableDropdownSelectionModel() | ||||
| @@ -176,6 +218,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|     this.dateAddedAfter = null | ||||
|     this.dateCreatedBefore = null | ||||
|     this.dateCreatedAfter = null | ||||
|     this.textFilterModifier = TEXT_FILTER_MODIFIER_EQUALS | ||||
|  | ||||
|     value.forEach((rule) => { | ||||
|       switch (rule.rule_type) { | ||||
| @@ -254,6 +297,20 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|             false | ||||
|           ) | ||||
|           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() | ||||
| @@ -273,8 +330,33 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|     if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_TITLE) { | ||||
|       filterRules.push({ rule_type: FILTER_TITLE, value: this._textFilter }) | ||||
|     } | ||||
|     if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_ASN) { | ||||
|       filterRules.push({ rule_type: FILTER_ASN, value: this._textFilter }) | ||||
|     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 }) | ||||
|       } 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 ( | ||||
|       this._textFilter && | ||||
| @@ -398,7 +480,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   get textFilter() { | ||||
|     return this._textFilter | ||||
|     return this.textFilterModifierIsNull ? '' : this._textFilter | ||||
|   } | ||||
|  | ||||
|   set textFilter(value) { | ||||
| @@ -498,4 +580,18 @@ export class FilterEditorComponent implements OnInit, OnDestroy { | ||||
|     this.textFilterInput.nativeElement.focus() | ||||
|     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_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_MORELIKE = 21 | ||||
| export const FILTER_FULLTEXT_QUERY = 22 | ||||
| export const FILTER_FULLTEXT_MORELIKE = 23 | ||||
|  | ||||
| export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|   { | ||||
| @@ -41,14 +43,12 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|     multi: false, | ||||
|     default: '', | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: FILTER_ASN, | ||||
|     filtervar: 'archive_serial_number', | ||||
|     datatype: 'number', | ||||
|     multi: false, | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: FILTER_CORRESPONDENT, | ||||
|     filtervar: 'correspondent__id', | ||||
| @@ -63,7 +63,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|     datatype: 'document_type', | ||||
|     multi: false, | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: FILTER_IS_IN_INBOX, | ||||
|     filtervar: 'is_in_inbox', | ||||
| @@ -96,7 +95,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|     multi: false, | ||||
|     default: true, | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: FILTER_CREATED_BEFORE, | ||||
|     filtervar: 'created__date__lt', | ||||
| @@ -109,7 +107,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|     datatype: 'date', | ||||
|     multi: false, | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: FILTER_CREATED_YEAR, | ||||
|     filtervar: 'created__year', | ||||
| @@ -141,7 +138,6 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|     datatype: 'date', | ||||
|     multi: false, | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: FILTER_MODIFIED_BEFORE, | ||||
|     filtervar: 'modified__date__lt', | ||||
| @@ -160,14 +156,24 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [ | ||||
|     datatype: 'boolean', | ||||
|     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, | ||||
|     filtervar: 'title_content', | ||||
|     datatype: 'string', | ||||
|     multi: false, | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: FILTER_FULLTEXT_QUERY, | ||||
|     filtervar: 'query', | ||||
|   | ||||
| @@ -261,6 +261,11 @@ textarea, | ||||
|   border-color: var(--bs-primary); | ||||
| } | ||||
|  | ||||
| .form-control:disabled, .form-control[readonly] { | ||||
|   background-color: var(--pngx-bg-alt); | ||||
|   cursor: not-allowed; | ||||
| } | ||||
|  | ||||
| .page-link { | ||||
|   color: var(--bs-secondary); | ||||
|   background-color: var(--bs-body-bg); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Quinn Casey
					Quinn Casey