mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	bulk edit menu and methods
This commit is contained in:
		| @@ -7,22 +7,19 @@ | |||||||
|       </svg> |       </svg> | ||||||
|       Bulk edit |       Bulk edit | ||||||
|     </button> |     </button> | ||||||
|     <div ngbDropdownMenu aria-labelledby="dropdownBasic1"> |     <div ngbDropdownMenu aria-labelledby="dropdownBasic1" class="shadow"> | ||||||
|       <button ngbDropdownItem>Select page</button> |       <button ngbDropdownItem (click)="list.selectPage()">Select page</button> | ||||||
|       <button ngbDropdownItem>Select all</button> |       <button ngbDropdownItem (click)="list.selectAll()">Select all</button> | ||||||
|       <button ngbDropdownItem>Select none</button> |       <button ngbDropdownItem (click)="list.selectNone()">Select none</button> | ||||||
|       <div class="dropdown-divider"></div> |       <div class="dropdown-divider"></div> | ||||||
|       <button ngbDropdownItem>Re-create archived document</button> |       <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkSetCorrespondent()">Set correspondent</button> | ||||||
|  |       <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkRemoveCorrespondent()">Remove correspondent</button> | ||||||
|  |       <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkSetDocumentType()">Set document type</button> | ||||||
|  |       <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkRemoveDocumentType()">Remove document type</button> | ||||||
|  |       <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkAddTag()">Add tag</button> | ||||||
|  |       <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkRemoveTag()">Remove tag</button> | ||||||
|       <div class="dropdown-divider"></div> |       <div class="dropdown-divider"></div> | ||||||
|       <button ngbDropdownItem>Set correspondent</button> |       <button ngbDropdownItem [disabled]="list.selected.size == 0" (click)="bulkDelete()">Delete</button> | ||||||
|       <button ngbDropdownItem>Remove correspondent</button> |  | ||||||
|       <button ngbDropdownItem>Set document type</button> |  | ||||||
|       <button ngbDropdownItem>Remove document type</button> |  | ||||||
|       <button ngbDropdownItem>Add tag</button> |  | ||||||
|       <button ngbDropdownItem>Remove tag</button> |  | ||||||
|       <div class="dropdown-divider"></div> |  | ||||||
|       <button ngbDropdownItem>Delete</button> |  | ||||||
|  |  | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  |  | ||||||
| @@ -101,7 +98,7 @@ | |||||||
| </div> | </div> | ||||||
|  |  | ||||||
| <div class="d-flex justify-content-between align-items-center"> | <div class="d-flex justify-content-between align-items-center"> | ||||||
|   <p>{{list.collectionSize || 0}} document(s) <span *ngIf="isFiltered">(filtered)</span></p> |   <p><span *ngIf="list.selected.size > 0">Selected {{list.selected.size}} of </span>{{list.collectionSize || 0}} document(s) <span *ngIf="isFiltered">(filtered)</span></p> | ||||||
|   <ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" [(page)]="list.currentPage" [maxSize]="5" |   <ngb-pagination [pageSize]="list.currentPageSize" [collectionSize]="list.collectionSize" [(page)]="list.currentPage" [maxSize]="5" | ||||||
|   [rotate]="true" (pageChange)="list.reload()" aria-label="Default pagination"></ngb-pagination> |   [rotate]="true" (pageChange)="list.reload()" aria-label="Default pagination"></ngb-pagination> | ||||||
| </div> | </div> | ||||||
| @@ -113,6 +110,7 @@ | |||||||
|  |  | ||||||
| <table class="table table-sm border shadow-sm" *ngIf="displayMode == 'details'"> | <table class="table table-sm border shadow-sm" *ngIf="displayMode == 'details'"> | ||||||
|   <thead> |   <thead> | ||||||
|  |     <th></th> | ||||||
|     <th class="d-none d-lg-table-cell">ASN</th> |     <th class="d-none d-lg-table-cell">ASN</th> | ||||||
|     <th class="d-none d-md-table-cell">Correspondent</th> |     <th class="d-none d-md-table-cell">Correspondent</th> | ||||||
|     <th>Title</th> |     <th>Title</th> | ||||||
| @@ -122,6 +120,12 @@ | |||||||
|   </thead> |   </thead> | ||||||
|   <tbody> |   <tbody> | ||||||
|     <tr *ngFor="let d of list.documents"> |     <tr *ngFor="let d of list.documents"> | ||||||
|  |       <td> | ||||||
|  |         <div class="custom-control custom-checkbox"> | ||||||
|  |           <input type="checkbox" class="custom-control-input" id="docCheck{{d.id}}" [checked]="list.isSelected(d)" (change)="list.setSelected(d, $event.target.checked)"> | ||||||
|  |           <label class="custom-control-label" for="docCheck{{d.id}}"></label> | ||||||
|  |         </div> | ||||||
|  |       </td> | ||||||
|       <td class="d-none d-lg-table-cell"> |       <td class="d-none d-lg-table-cell"> | ||||||
|         {{d.archive_serial_number}} |         {{d.archive_serial_number}} | ||||||
|       </td> |       </td> | ||||||
|   | |||||||
| @@ -2,14 +2,21 @@ import { Component, OnInit } from '@angular/core'; | |||||||
| import { Title } from '@angular/platform-browser'; | import { Title } from '@angular/platform-browser'; | ||||||
| import { ActivatedRoute } from '@angular/router'; | import { ActivatedRoute } from '@angular/router'; | ||||||
| import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; | import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; | ||||||
|  | import { Observable } from 'rxjs'; | ||||||
|  | import { map } from 'rxjs/operators'; | ||||||
| import { cloneFilterRules, FilterRule } from 'src/app/data/filter-rule'; | import { cloneFilterRules, FilterRule } from 'src/app/data/filter-rule'; | ||||||
| import { FILTER_CORRESPONDENT, FILTER_DOCUMENT_TYPE, FILTER_HAS_TAG, FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type'; | import { FILTER_CORRESPONDENT, FILTER_DOCUMENT_TYPE, FILTER_HAS_TAG, FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type'; | ||||||
| import { SavedViewConfig } from 'src/app/data/saved-view-config'; | import { SavedViewConfig } from 'src/app/data/saved-view-config'; | ||||||
| import { DocumentListViewService } from 'src/app/services/document-list-view.service'; | import { DocumentListViewService } from 'src/app/services/document-list-view.service'; | ||||||
| import { DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service'; | import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; | ||||||
|  | import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; | ||||||
|  | import { DocumentService, DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/document.service'; | ||||||
|  | import { TagService } from 'src/app/services/rest/tag.service'; | ||||||
| import { SavedViewConfigService } from 'src/app/services/saved-view-config.service'; | import { SavedViewConfigService } from 'src/app/services/saved-view-config.service'; | ||||||
| import { Toast, ToastService } from 'src/app/services/toast.service'; | import { Toast, ToastService } from 'src/app/services/toast.service'; | ||||||
| import { environment } from 'src/environments/environment'; | import { environment } from 'src/environments/environment'; | ||||||
|  | import { DeleteDialogComponent } from '../common/delete-dialog/delete-dialog.component'; | ||||||
|  | import { SelectDialogComponent } from '../common/select-dialog/select-dialog.component'; | ||||||
| import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'; | import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'; | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
| @@ -25,7 +32,11 @@ export class DocumentListComponent implements OnInit { | |||||||
|     public route: ActivatedRoute, |     public route: ActivatedRoute, | ||||||
|     private toastService: ToastService, |     private toastService: ToastService, | ||||||
|     public modalService: NgbModal, |     public modalService: NgbModal, | ||||||
|     private titleService: Title) { } |     private titleService: Title, | ||||||
|  |     private correspondentService: CorrespondentService, | ||||||
|  |     private documentTypeService: DocumentTypeService, | ||||||
|  |     private tagService: TagService, | ||||||
|  |     private documentService: DocumentService) { } | ||||||
|  |  | ||||||
|   displayMode = 'smallCards' // largeCards, smallCards, details |   displayMode = 'smallCards' // largeCards, smallCards, details | ||||||
|  |  | ||||||
| @@ -142,4 +153,101 @@ export class DocumentListComponent implements OnInit { | |||||||
|     this.applyFilterRules() |     this.applyFilterRules() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private executeBulkOperation(method: string, args): Observable<any> { | ||||||
|  |     return this.documentService.bulkEdit(Array.from(this.list.selected), method, args).pipe( | ||||||
|  |       map(r => { | ||||||
|  |  | ||||||
|  |         this.list.reload() | ||||||
|  |         this.list.selectNone() | ||||||
|  |  | ||||||
|  |         return r | ||||||
|  |       }) | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkSetCorrespondent() { | ||||||
|  |     let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = "Select correspondent" | ||||||
|  |     modal.componentInstance.message = `Select the correspondent you wish to assign to ${this.list.selected.size} selected document(s):` | ||||||
|  |     this.correspondentService.listAll().subscribe(response => { | ||||||
|  |       modal.componentInstance.objects = response.results | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.selectClicked.subscribe(selectedId => { | ||||||
|  |       this.executeBulkOperation('set_correspondent', {"correspondent": selectedId}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkRemoveCorrespondent() { | ||||||
|  |     this.executeBulkOperation('set_correspondent', {"correspondent": null}).subscribe(r => {}) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkSetDocumentType() { | ||||||
|  |     let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = "Select document type" | ||||||
|  |     modal.componentInstance.message = `Select the document type you wish to assign to ${this.list.selected.size} selected document(s):` | ||||||
|  |     this.documentTypeService.listAll().subscribe(response => { | ||||||
|  |       modal.componentInstance.objects = response.results | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.selectClicked.subscribe(selectedId => { | ||||||
|  |       this.executeBulkOperation('set_document_type', {"document_type": selectedId}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkRemoveDocumentType() { | ||||||
|  |     this.executeBulkOperation('set_document_type', {"document_type": null}).subscribe(r => {}) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkAddTag() { | ||||||
|  |     let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = "Select tag" | ||||||
|  |     modal.componentInstance.message = `Select the tag you wish to assign to ${this.list.selected.size} selected document(s):` | ||||||
|  |     this.tagService.listAll().subscribe(response => { | ||||||
|  |       modal.componentInstance.objects = response.results | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.selectClicked.subscribe(selectedId => { | ||||||
|  |       this.executeBulkOperation('add_tag', {"tag": selectedId}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkRemoveTag() { | ||||||
|  |     let modal = this.modalService.open(SelectDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = "Select tag" | ||||||
|  |     modal.componentInstance.message = `Select the tag you wish to remove from ${this.list.selected.size} selected document(s):` | ||||||
|  |     this.tagService.listAll().subscribe(response => { | ||||||
|  |       modal.componentInstance.objects = response.results | ||||||
|  |     }) | ||||||
|  |     modal.componentInstance.selectClicked.subscribe(selectedId => { | ||||||
|  |       this.executeBulkOperation('remove_tag', {"tag": selectedId}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bulkDelete() { | ||||||
|  |     let modal = this.modalService.open(DeleteDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.delayConfirm(5) | ||||||
|  |     modal.componentInstance.message = `This operation will permanently delete all ${this.list.selected.size} selected document(s).` | ||||||
|  |     modal.componentInstance.message2 = `This operation cannot be undone.` | ||||||
|  |     modal.componentInstance.deleteClicked.subscribe(() => { | ||||||
|  |       this.executeBulkOperation("delete", {}).subscribe( | ||||||
|  |         response => { | ||||||
|  |           modal.close() | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     })     | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 jonaswinkler
					jonaswinkler