mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	UI for matching api
This commit is contained in:
		
							
								
								
									
										37
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										37
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -10794,6 +10794,12 @@ | ||||
|           "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", | ||||
|           "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "uuid": { | ||||
|           "version": "3.4.0", | ||||
|           "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", | ||||
|           "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", | ||||
|           "dev": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| @@ -11725,6 +11731,14 @@ | ||||
|         "faye-websocket": "^0.10.0", | ||||
|         "uuid": "^3.4.0", | ||||
|         "websocket-driver": "0.6.5" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "uuid": { | ||||
|           "version": "3.4.0", | ||||
|           "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", | ||||
|           "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", | ||||
|           "dev": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "sockjs-client": { | ||||
| @@ -12800,6 +12814,14 @@ | ||||
|         "debug": "^4.1.1", | ||||
|         "request": "^2.88.2", | ||||
|         "uuid": "^3.0.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "uuid": { | ||||
|           "version": "3.4.0", | ||||
|           "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", | ||||
|           "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", | ||||
|           "dev": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "universalify": { | ||||
| @@ -12987,10 +13009,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "uuid": { | ||||
|       "version": "3.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", | ||||
|       "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", | ||||
|       "dev": true | ||||
|       "version": "8.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", | ||||
|       "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" | ||||
|     }, | ||||
|     "validate-npm-package-license": { | ||||
|       "version": "3.0.4", | ||||
| @@ -13920,6 +13941,14 @@ | ||||
|       "requires": { | ||||
|         "ansi-colors": "^3.0.0", | ||||
|         "uuid": "^3.3.2" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "uuid": { | ||||
|           "version": "3.4.0", | ||||
|           "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", | ||||
|           "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", | ||||
|           "dev": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "webpack-merge": { | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
|     "ngx-file-drop": "^10.0.0", | ||||
|     "rxjs": "~6.6.0", | ||||
|     "tslib": "^2.0.0", | ||||
|     "uuid": "^8.3.1", | ||||
|     "zone.js": "~0.10.2" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'; | ||||
| import { Form, FormGroup } from '@angular/forms'; | ||||
| import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; | ||||
| import { Observable } from 'rxjs'; | ||||
| import { MatchingModel } from 'src/app/data/matching-model'; | ||||
| import { ObjectWithId } from 'src/app/data/object-with-id'; | ||||
| import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'; | ||||
| import { Toast, ToastService } from 'src/app/services/toast.service'; | ||||
| @@ -45,6 +46,10 @@ export abstract class EditDialogComponent<T extends ObjectWithId> implements OnI | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   getMatchingAlgorithms() { | ||||
|     return MatchingModel.MATCHING_ALGORITHMS | ||||
|   } | ||||
|  | ||||
|   save() { | ||||
|     var newObject = Object.assign(Object.assign({}, this.object), this.objectForm.value) | ||||
|     var serverResponse: Observable<T> | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|     <div class="col"> | ||||
|       <div class="card-body"> | ||||
|  | ||||
|         <h5 class="card-title">{{document.title}}<app-tag [tag]="t" *ngFor="let t of document.tags" class="ml-1"></app-tag></h5> | ||||
|         <h5 class="card-title">{{document.correspondent ? document.correspondent.name + ': ' : ''}}{{document.title}}<app-tag [tag]="t" *ngFor="let t of document.tags" class="ml-1"></app-tag></h5> | ||||
|         <p class="card-text"> | ||||
|           <app-result-hightlight *ngIf="getDetailsAsHighlight()" class="result-content" [highlights]="getDetailsAsHighlight()"></app-result-hightlight> | ||||
|           <span *ngIf="getDetailsAsString()" class="result-content">{{getDetailsAsString()}}</span> | ||||
|   | ||||
| @@ -6,15 +6,12 @@ | ||||
|     </button> | ||||
|   </div> | ||||
|   <div class="modal-body"> | ||||
|     <div class="form-group"> | ||||
|       <label for="name">Name</label> | ||||
|       <input id="name" class="form-control" formControlName="name" required ngbAutofocus> | ||||
|     </div> | ||||
|     <div class="form-group form-check"> | ||||
|       <input type="checkbox" class="form-check-input" id="automatic_classification" | ||||
|         formControlName="automatic_classification"> | ||||
|       <label class="form-check-label" for="automatic_classification">Automatic Classification</label> | ||||
|     </div> | ||||
|      | ||||
|     <app-input-text title="Name" formControlName="name"></app-input-text> | ||||
|     <app-input-text title="Match" formControlName="match"></app-input-text> | ||||
|     <app-input-select title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|     <app-input-check title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|  | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|     <button type="button" class="btn btn-outline-dark" (click)="cancel()">Cancel</button> | ||||
|   | ||||
| @@ -20,7 +20,9 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent<Paperl | ||||
|   getForm(): FormGroup { | ||||
|     return new FormGroup({ | ||||
|       name: new FormControl(''), | ||||
|       automatic_classification: new FormControl(true) | ||||
|       matching_algorithm: new FormControl(1), | ||||
|       match: new FormControl(""), | ||||
|       is_insensitive: new FormControl(true) | ||||
|     }) | ||||
|   }   | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|     <thead> | ||||
|     <tr> | ||||
|       <th scope="col">Name</th> | ||||
|       <th scope="col">Automatic Classification</th> | ||||
|       <th scope="col">Matching</th> | ||||
|       <th scope="col">Document count</th> | ||||
|       <th scope="col">Last correspondence</th> | ||||
|       <th scope="col">Actions</th> | ||||
| @@ -19,7 +19,7 @@ | ||||
|     <tbody> | ||||
|     <tr *ngFor="let correspondent of data"> | ||||
|       <td scope="row">{{ correspondent.name }}</td> | ||||
|       <td scope="row">{{ correspondent.automatic_classification }}</td> | ||||
|       <td scope="row">{{ getMatching(correspondent) }}</td> | ||||
|       <td scope="row">{{ correspondent.document_count }}</td> | ||||
|       <td scope="row">{{ correspondent.last_correspondence | date }}</td> | ||||
|         <td scope="row"> | ||||
|   | ||||
| @@ -6,15 +6,12 @@ | ||||
|       </button> | ||||
|     </div> | ||||
|     <div class="modal-body"> | ||||
|       <div class="form-group"> | ||||
|         <label for="name">Name</label> | ||||
|         <input id="name" class="form-control" formControlName="name" required ngbAutofocus> | ||||
|       </div> | ||||
|       <div class="form-group form-check"> | ||||
|         <input type="checkbox" class="form-check-input" id="automatic_classification" | ||||
|           formControlName="automatic_classification"> | ||||
|         <label class="form-check-label" for="automatic_classification">Automatic Classification</label> | ||||
|       </div> | ||||
|        | ||||
|       <app-input-text title="Name" formControlName="name"></app-input-text> | ||||
|       <app-input-text title="Match" formControlName="match"></app-input-text> | ||||
|       <app-input-select title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|       <app-input-check title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|  | ||||
|     </div> | ||||
|     <div class="modal-footer"> | ||||
|       <button type="button" class="btn btn-outline-dark" (click)="cancel()">Cancel</button> | ||||
|   | ||||
| @@ -20,7 +20,9 @@ export class DocumentTypeEditDialogComponent extends EditDialogComponent<Paperle | ||||
|   getForm(): FormGroup { | ||||
|     return new FormGroup({ | ||||
|       name: new FormControl(''), | ||||
|       automatic_classification: new FormControl(true) | ||||
|       matching_algorithm: new FormControl(1), | ||||
|       match: new FormControl(""), | ||||
|       is_insensitive: new FormControl(true) | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -11,20 +11,20 @@ | ||||
|   <thead> | ||||
|     <tr> | ||||
|       <th scope="col">Name</th> | ||||
|       <th scope="col">Automatic Classification</th> | ||||
|       <th scope="col">Matching</th> | ||||
|       <th scope="col">Document count</th> | ||||
|       <th scope="col">Actions</th> | ||||
|     </tr> | ||||
|   </thead> | ||||
|   <tbody> | ||||
|     <tr *ngFor="let correspondent of data"> | ||||
|       <td scope="row">{{ correspondent.name }}</td> | ||||
|       <td scope="row">{{ correspondent.automatic_classification }}</td> | ||||
|       <td scope="row">{{ correspondent.document_count }}</td> | ||||
|     <tr *ngFor="let document_type of data"> | ||||
|       <td scope="row">{{ document_type.name }}</td> | ||||
|       <td scope="row">{{ getMatching(document_type) }}</td> | ||||
|       <td scope="row">{{ document_type.document_count }}</td> | ||||
|       <td scope="row"> | ||||
|         <div class="btn-group"> | ||||
|           <button class="btn btn-sm btn-outline-secondary" (click)="openEditDialog(correspondent)">Edit</button> | ||||
|           <button class="btn btn-sm btn-outline-danger" (click)="openDeleteDialog(correspondent)">Delete</button> | ||||
|           <button class="btn btn-sm btn-outline-secondary" (click)="openEditDialog(document_type)">Edit</button> | ||||
|           <button class="btn btn-sm btn-outline-danger" (click)="openDeleteDialog(document_type)">Delete</button> | ||||
|         </div> | ||||
|       </td> | ||||
|     </tr> | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { Directive, OnInit } from '@angular/core'; | ||||
| import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; | ||||
| import { MatchingModel } from 'src/app/data/matching-model'; | ||||
| import { ObjectWithId } from 'src/app/data/object-with-id'; | ||||
| import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'; | ||||
| import { DeleteDialogComponent } from '../../common/delete-dialog/delete-dialog.component'; | ||||
| @@ -19,6 +20,16 @@ export abstract class GenericListComponent<T extends ObjectWithId> implements On | ||||
|  | ||||
|   public collectionSize = 0 | ||||
|  | ||||
|   getMatching(o: MatchingModel) { | ||||
|     if (o.matching_algorithm == MatchingModel.MATCH_AUTO) { | ||||
|       return "Automatic" | ||||
|     } else if (o.match && o.match.length > 0) { | ||||
|       return `${o.match} (${MatchingModel.MATCHING_ALGORITHMS.find(a => a.id == o.matching_algorithm).name})` | ||||
|     } else { | ||||
|       return "-" | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     this.reloadData() | ||||
|   } | ||||
|   | ||||
| @@ -6,26 +6,12 @@ | ||||
|       </button> | ||||
|     </div> | ||||
|     <div class="modal-body"> | ||||
|       <div class="form-group"> | ||||
|         <label for="name">Name</label> | ||||
|         <input id="name" class="form-control" formControlName="name" required ngbAutofocus> | ||||
|       </div> | ||||
|       <div class="form-group"> | ||||
|         <label for="colour">Colour</label> | ||||
|         <select id="colour" class="form-control" required formControlName="colour" [style.color]="getColor(objectForm.value.colour).textColor" [style.background]="getColor(objectForm.value.colour).value"> | ||||
|           <option *ngFor="let colour of getColours()" [ngValue]="colour.id" class="form-control">{{colour.name}}</option> | ||||
|         </select> | ||||
|       </div> | ||||
|       <div class="form-group form-check"> | ||||
|         <input type="checkbox" class="form-check-input" id="is_inbox_tag" | ||||
|           formControlName="is_inbox_tag"> | ||||
|         <label class="form-check-label" for="is_inbox_tag">Inbox Tag</label> | ||||
|       </div> | ||||
|       <div class="form-group form-check"> | ||||
|         <input type="checkbox" class="form-check-input" id="automatic_classification" | ||||
|           formControlName="automatic_classification"> | ||||
|         <label class="form-check-label" for="automatic_classification">Automatic Classification</label> | ||||
|       </div> | ||||
|       <app-input-text title="Name" formControlName="name"></app-input-text> | ||||
|       <app-input-select title="Colour" [items]="getColours()" formControlName="colour" [textColor]="getColor(objectForm.value.colour).textColor" [backgroundColor]="getColor(objectForm.value.colour).value"></app-input-select> | ||||
|       <app-input-check title="Inbox tag" formControlName="is_inbox_tag" hint="Inbox tags are automatically assigned to all consumed documents."></app-input-check> | ||||
|       <app-input-text title="Match" formControlName="match"></app-input-text> | ||||
|       <app-input-select title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|       <app-input-check title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|     </div> | ||||
|     <div class="modal-footer"> | ||||
|       <button type="button" class="btn btn-outline-dark" (click)="cancel()">Cancel</button> | ||||
|   | ||||
| @@ -22,7 +22,9 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> { | ||||
|       name: new FormControl(''), | ||||
|       colour: new FormControl(1), | ||||
|       is_inbox_tag: new FormControl(false), | ||||
|       automatic_classification: new FormControl(true) | ||||
|       matching_algorithm: new FormControl(1), | ||||
|       match: new FormControl(""), | ||||
|       is_insensitive: new FormControl(true) | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|       <tr> | ||||
|         <th scope="col">Name</th> | ||||
|         <th scope="col">Colour</th> | ||||
|         <th scope="col">Automatic Classification</th> | ||||
|         <th scope="col">Matching</th> | ||||
|         <th scope="col">Document count</th> | ||||
|         <th scope="col">Actions</th> | ||||
|       </tr> | ||||
| @@ -20,7 +20,7 @@ | ||||
|       <tr *ngFor="let tag of data"> | ||||
|           <td scope="row">{{ tag.name }}</td> | ||||
|           <td scope="row"><span class="badge" [style.color]="getColor(tag.colour).textColor" [style.background-color]="getColor(tag.colour).value">{{ getColor(tag.colour).name }}</span></td> | ||||
|           <td scope="row">{{ tag.automatic_classification }}</td> | ||||
|           <td scope="row">{{ getMatching(tag) }}</td> | ||||
|           <td scope="row">{{ tag.document_count }}</td> | ||||
|           <td scope="row"> | ||||
|             <div class="btn-group"> | ||||
|   | ||||
| @@ -2,10 +2,30 @@ import { ObjectWithId } from './object-with-id'; | ||||
|  | ||||
| export class MatchingModel extends ObjectWithId { | ||||
|  | ||||
|     static MATCH_ANY = 1 | ||||
|     static MATCH_ALL = 2 | ||||
|     static MATCH_LITERAL = 3 | ||||
|     static MATCH_REGEX = 4 | ||||
|     static MATCH_FUZZY = 5 | ||||
|     static MATCH_AUTO = 6 | ||||
|  | ||||
|     static MATCHING_ALGORITHMS = [ | ||||
|         {id: MatchingModel.MATCH_ANY, name: "Any"}, | ||||
|         {id: MatchingModel.MATCH_ALL, name: "All"}, | ||||
|         {id: MatchingModel.MATCH_LITERAL, name: "Literal"}, | ||||
|         {id: MatchingModel.MATCH_REGEX, name: "Regular Expression"}, | ||||
|         {id: MatchingModel.MATCH_FUZZY, name: "Fuzzy Match"}, | ||||
|         {id: MatchingModel.MATCH_AUTO, name: "Auto"}, | ||||
|     ] | ||||
|  | ||||
|     name?: string | ||||
|  | ||||
|     slug?: string | ||||
|  | ||||
|     automatic_classification?: boolean | ||||
|     match?: string | ||||
|  | ||||
|     matching_algorithm?: number | ||||
|  | ||||
|     is_insensitive?: boolean | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonas Winkler
					Jonas Winkler